2 * $Id: afp_config.c,v 1.22 2003-02-09 20:34:38 jmarcus Exp $
4 * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
20 #else /* STDC_HEADERS */
24 #endif /* HAVE_STRCHR */
25 char *strchr (), *strrchr ();
27 #define memcpy(d,s,n) bcopy ((s), (d), (n))
28 #define memmove(d,s,n) bcopy ((s), (d), (n))
29 #endif /* ! HAVE_MEMCPY */
30 #endif /* STDC_HEADERS */
34 #endif /* HAVE_UNISTD_H */
36 #include <atalk/logger.h>
38 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
42 #include <atalk/dsi.h>
43 #include <atalk/atp.h>
44 #include <atalk/asp.h>
45 #include <atalk/nbp.h>
46 #include <atalk/afp.h>
47 #include <atalk/compat.h>
48 #include <atalk/server_child.h>
51 static char srvloc_url[512];
52 #endif /* USE_SRVLOC */
55 #include "afp_config.h"
61 /* get rid of unneeded configurations. i use reference counts to deal
62 * w/ multiple configs sharing the same afp_options. oh, to dream of
63 * garbage collection ... */
64 void configfree(AFPConfig *configs, const AFPConfig *config)
68 for (p = configs; p; p = q) {
73 /* do a little reference counting */
74 if (--(*p->optcount) < 1) {
75 afp_options_free(&p->obj.options, p->defoptions);
79 switch (p->obj.proto) {
85 atp_close(((ASP) p->obj.handle)->asp_atp);
88 #endif /* no afp/asp */
99 static void SRVLOC_callback(SLPHandle hslp, SLPError errcode, void *cookie) {
100 *(SLPError*)cookie = errcode;
102 #endif /* USE_SRVLOC */
105 static void dsi_cleanup(const AFPConfig *config)
108 SLPError callbackerr;
111 /* Do nothing if we didn't register. */
112 if (srvloc_url[0] == '\0')
115 err = SLPOpen("en", SLP_FALSE, &hslp);
117 LOG(log_error, logtype_afpd, "dsi_cleanup: Error opening SRVLOC handle");
118 goto srvloc_dereg_err;
126 LOG(log_error, logtype_afpd, "dsi_cleanup: Error unregistering %s from SRVLOC", srvloc_url);
127 goto srvloc_dereg_err;
130 if (callbackerr != SLP_OK) {
131 LOG(log_error, logtype_afpd, "dsi_cleanup: Error in callback while trying to unregister %s from SRVLOC (%d)", srvloc_url, callbackerr);
132 goto srvloc_dereg_err;
138 #endif /* USE_SRVLOC */
141 static void asp_cleanup(const AFPConfig *config)
143 nbp_unrgstr(config->obj.Obj, config->obj.Type, config->obj.Zone,
144 &config->obj.options.ddpaddr);
147 /* these two are almost identical. it should be possible to collapse them
148 * into one with minimal junk. */
149 static int asp_start(AFPConfig *config, AFPConfig *configs,
150 server_child *server_children)
154 if (!(asp = asp_getsession(config->obj.handle, server_children,
155 config->obj.options.tickleval))) {
156 LOG(log_error, logtype_afpd, "main: asp_getsession: %s", strerror(errno) );
161 configfree(configs, config); /* free a bunch of stuff */
162 afp_over_asp(&config->obj);
168 #endif /* no afp/asp */
170 static int dsi_start(AFPConfig *config, AFPConfig *configs,
171 server_child *server_children)
175 if (!(dsi = dsi_getsession(config->obj.handle, server_children,
176 config->obj.options.tickleval))) {
177 LOG(log_error, logtype_afpd, "main: dsi_getsession: %s", strerror(errno) );
183 configfree(configs, config);
184 afp_over_dsi(&config->obj); /* start a session */
192 static AFPConfig *ASPConfigInit(const struct afp_options *options,
193 unsigned char *refcount)
198 char *Obj, *Type = "AFPServer", *Zone = "*";
200 if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL)
203 if ((atp = atp_open(ATADDR_ANYPORT, &options->ddpaddr)) == NULL) {
204 LOG(log_error, logtype_afpd, "main: atp_open: %s", strerror(errno) );
209 if ((asp = asp_init( atp )) == NULL) {
210 LOG(log_error, logtype_afpd, "main: asp_init: %s", strerror(errno) );
216 /* register asp server */
217 Obj = (char *) options->hostname;
218 if (nbp_name(options->server, &Obj, &Type, &Zone )) {
219 LOG(log_error, logtype_afpd, "main: can't parse %s", options->server );
220 goto serv_free_return;
223 /* dup Obj, Type and Zone as they get assigned to a single internal
224 * buffer by nbp_name */
225 if ((config->obj.Obj = strdup(Obj)) == NULL)
226 goto serv_free_return;
228 if ((config->obj.Type = strdup(Type)) == NULL) {
229 free(config->obj.Obj);
230 goto serv_free_return;
233 if ((config->obj.Zone = strdup(Zone)) == NULL) {
234 free(config->obj.Obj);
235 free(config->obj.Type);
236 goto serv_free_return;
239 /* make sure we're not registered */
240 nbp_unrgstr(Obj, Type, Zone, &options->ddpaddr);
241 if (nbp_rgstr( atp_sockaddr( atp ), Obj, Type, Zone ) < 0 ) {
242 LOG(log_error, logtype_afpd, "Can't register %s:%s@%s", Obj, Type, Zone );
243 free(config->obj.Obj);
244 free(config->obj.Type);
245 free(config->obj.Zone);
246 goto serv_free_return;
249 LOG(log_info, logtype_afpd, "%s:%s@%s started on %u.%u:%u (%s)", Obj, Type, Zone,
250 ntohs( atp_sockaddr( atp )->sat_addr.s_net ),
251 atp_sockaddr( atp )->sat_addr.s_node,
252 atp_sockaddr( atp )->sat_port, VERSION );
254 config->fd = atp_fileno(atp);
255 config->obj.handle = asp;
256 config->obj.config = config;
257 config->obj.proto = AFPPROTO_ASP;
259 memcpy(&config->obj.options, options, sizeof(struct afp_options));
260 config->optcount = refcount;
263 config->server_start = asp_start;
264 config->server_cleanup = asp_cleanup;
273 #endif /* no afp/asp */
276 static AFPConfig *DSIConfigInit(const struct afp_options *options,
277 unsigned char *refcount,
278 const dsi_proto protocol)
285 SLPError callbackerr;
287 struct servent *afpovertcp;
289 const char *srvloc_hostname, *hostname;
291 #endif /* USE_SRVLOC */
293 if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL) {
294 LOG(log_error, logtype_afpd, "DSIConfigInit: malloc(config): %s", strerror(errno) );
298 if ((dsi = dsi_init(protocol, "afpd", options->hostname,
299 options->ipaddr, options->port,
300 options->flags & OPTION_PROXY,
301 options->server_quantum)) == NULL) {
302 LOG(log_error, logtype_afpd, "main: dsi_init: %s", strerror(errno) );
307 if (options->flags & OPTION_PROXY) {
308 LOG(log_info, logtype_afpd, "ASIP proxy initialized for %s:%d (%s)",
309 inet_ntoa(dsi->server.sin_addr), ntohs(dsi->server.sin_port),
312 LOG(log_info, logtype_afpd, "ASIP started on %s:%d(%d) (%s)",
313 inet_ntoa(dsi->server.sin_addr), ntohs(dsi->server.sin_port),
314 dsi->serversock, VERSION);
318 srvloc_url[0] = '\0'; /* Mark that we haven't registered. */
319 if (!(options->flags & OPTION_NOSLP)) {
320 err = SLPOpen("en", SLP_FALSE, &hslp);
322 LOG(log_error, logtype_afpd, "DSIConfigInit: Error opening SRVLOC handle");
326 /* XXX We don't want to tack on the port number if we don't have to.
328 * Well, this seems to break MacOS < 10. If the user _really_ wants to
329 * use a non-default port, they can, but be aware, this server might
330 * not show up int the Network Browser.
332 afpovertcp = getservbyname("afpovertcp", "tcp");
333 if (afpovertcp != NULL) {
334 afp_port = afpovertcp->s_port;
336 /* Try to use the FQDN to register with srvloc. */
337 h = gethostbyaddr((char*)&dsi->server.sin_addr, sizeof(dsi->server.sin_addr), AF_INET);
338 if (h) hostname = h->h_name;
339 else hostname = inet_ntoa(dsi->server.sin_addr);
340 srvloc_hostname = (options->server ? options->server : options->hostname);
341 if (strlen(srvloc_hostname) > (sizeof(srvloc_url) - strlen(hostname) - 21)) {
342 LOG(log_error, logtype_afpd, "DSIConfigInit: Hostname is too long for SRVLOC");
343 srvloc_url[0] = '\0';
346 if (dsi->server.sin_port == afp_port) {
347 sprintf(srvloc_url, "afp://%s/?NAME=%s", hostname, srvloc_hostname);
350 sprintf(srvloc_url, "afp://%s:%d/?NAME=%s", hostname, ntohs(dsi->server.sin_port), srvloc_hostname);
355 SLP_LIFETIME_MAXIMUM,
362 LOG(log_error, logtype_afpd, "DSIConfigInit: Error registering %s with SRVLOC", srvloc_url);
363 srvloc_url[0] = '\0';
367 if (callbackerr != SLP_OK) {
368 LOG(log_error, logtype_afpd, "DSIConfigInit: Error in callback trying to register %s with SRVLOC", srvloc_url);
369 srvloc_url[0] = '\0';
373 LOG(log_info, logtype_afpd, "Sucessfully registered %s with SRVLOC", srvloc_url);
378 #endif /* USE_SRVLOC */
381 config->fd = dsi->serversock;
382 config->obj.handle = dsi;
383 config->obj.config = config;
384 config->obj.proto = AFPPROTO_DSI;
386 memcpy(&config->obj.options, options, sizeof(struct afp_options));
387 /* get rid of any appletalk info. we use the fact that the DSI
388 * stuff is done after the ASP stuff. */
389 p = config->obj.options.server;
390 if (p && (q = strchr(p, ':')))
393 config->optcount = refcount;
396 config->server_start = dsi_start;
398 config->server_cleanup = dsi_cleanup;
399 #endif /* USE_SRVLOC */
403 /* allocate server configurations. this should really store the last
404 * entry in config->last or something like that. that would make
405 * supporting multiple dsi transports easier. */
406 static AFPConfig *AFPConfigInit(const struct afp_options *options,
407 const struct afp_options *defoptions)
409 AFPConfig *config = NULL, *next = NULL;
410 unsigned char *refcount;
412 if ((refcount = (unsigned char *)
413 calloc(1, sizeof(unsigned char))) == NULL) {
414 LOG(log_error, logtype_afpd, "AFPConfigInit: calloc(refcount): %s", strerror(errno) );
419 /* handle asp transports */
420 if ((options->transports & AFPTRANS_DDP) &&
421 (config = ASPConfigInit(options, refcount)))
422 config->defoptions = defoptions;
425 /* handle dsi transports and dsi proxies. we only proxy
426 * for DSI connections. */
428 /* this should have something like the following:
429 * for (i=mindsi; i < maxdsi; i++)
430 * if (options->transports & (1 << i) &&
431 * (next = DSIConfigInit(options, refcount, i)))
432 * next->defoptions = defoptions;
434 if ((options->transports & AFPTRANS_TCP) &&
435 (((options->flags & OPTION_PROXY) == 0) ||
436 ((options->flags & OPTION_PROXY) && config))
437 && (next = DSIConfigInit(options, refcount, DSI_TCPIP)))
438 next->defoptions = defoptions;
440 /* load in all the authentication modules. we can load the same
441 things multiple times if necessary. however, loading different
442 things with the same names will cause complaints. by not loading
443 in any uams with proxies, we prevent ddp connections from succeeding.
445 auth_load(options->uampath, options->uamlist);
447 /* this should be able to accept multiple dsi transports. i think
448 * the only thing that gets affected is the net addresses. */
449 status_init(config, next, options);
451 /* attach dsi config to tail of asp config */
460 /* fill in the appropriate bits for each interface */
461 AFPConfig *configinit(struct afp_options *cmdline)
464 char buf[LINESIZE + 1], *p, have_option = 0;
465 struct afp_options options;
466 AFPConfig *config, *first = NULL;
468 /* if config file doesn't exist, load defaults */
469 if ((fp = fopen(cmdline->configfile, "r")) == NULL)
471 LOG(log_debug, logtype_afpd, "ConfigFile %s not found, assuming defaults",
472 cmdline->configfile);
473 return AFPConfigInit(cmdline, cmdline);
476 LOG(log_debug, logtype_afpd, "Loading ConfigFile");
478 /* scan in the configuration file */
480 if (!fgets(buf, sizeof(buf), fp) || buf[0] == '#')
483 /* a little pre-processing to get rid of spaces and end-of-lines */
485 while (p && isspace(*p))
487 if (!p || (*p == '\0'))
492 memcpy(&options, cmdline, sizeof(options));
493 if (!afp_options_parseline(p, &options))
496 /* this should really get a head and a tail to simplify things. */
498 if ((first = AFPConfigInit(&options, cmdline)))
499 config = first->next ? first->next : first;
500 } else if ((config->next = AFPConfigInit(&options, cmdline))) {
501 config = config->next->next ? config->next->next : config->next;
505 LOG(log_debug, logtype_afpd, "Finished parsing Config File");
509 return AFPConfigInit(cmdline, cmdline);