2 * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
3 * All Rights Reserved. See COPYRIGHT.
8 #endif /* HAVE_CONFIG_H */
18 #else /* STDC_HEADERS */
22 #endif /* HAVE_STRCHR */
23 char *strchr (), *strrchr ();
25 #define memcpy(d,s,n) bcopy ((s), (d), (n))
26 #define memmove(d,s,n) bcopy ((s), (d), (n))
27 #endif /* ! HAVE_MEMCPY */
28 #endif /* STDC_HEADERS */
32 #endif /* HAVE_UNISTD_H */
34 #include <atalk/logger.h>
35 #include <atalk/util.h>
37 #include <sys/socket.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
41 #include <atalk/dsi.h>
42 #include <atalk/atp.h>
43 #include <atalk/asp.h>
44 #include <atalk/nbp.h>
45 #include <atalk/afp.h>
46 #include <atalk/compat.h>
47 #include <atalk/server_child.h>
50 #endif /* USE_SRVLOC */
52 #include <atalk/ldapconfig.h>
56 #include "afp_config.h"
62 /* get rid of unneeded configurations. i use reference counts to deal
63 * w/ multiple configs sharing the same afp_options. oh, to dream of
64 * garbage collection ... */
65 void configfree(AFPConfig *configs, const AFPConfig *config)
69 for (p = configs; p; p = q) {
74 /* do a little reference counting */
75 if (--(*p->optcount) < 1) {
76 afp_options_free(&p->obj.options, p->defoptions);
80 switch (p->obj.proto) {
86 atp_close(((ASP) p->obj.handle)->asp_atp);
89 #endif /* no afp/asp */
100 static void SRVLOC_callback(SLPHandle hslp _U_, SLPError errcode, void *cookie) {
101 *(SLPError*)cookie = errcode;
104 static char hex[17] = "0123456789abcdef";
106 static char * srvloc_encode(const struct afp_options *options, const char *name)
108 static char buf[512];
113 char *Obj, *Type = "", *Zone = "";
116 /* Convert name to maccharset */
117 if ((size_t)-1 ==(convert_string_allocate( options->unixcharset, options->maccharset,
118 name, -1, &conv_name)) )
121 /* Escape characters */
123 while (*p && i<(sizeof(buf)-4)) {
126 else if (isspace(*p)) {
132 else if ((!isascii(*p)) || *p <= 0x2f || *p == 0x3f ) {
134 buf[i++] = hex[*p >> 4];
135 buf[i++] = hex[*p++ & 15];
145 if (nbp_name(options->server, &Obj, &Type, &Zone )) {
146 LOG(log_error, logtype_afpd, "srvloc_encode: can't parse %s", options->server );
149 snprintf( buf+i, sizeof(buf)-i-1 ,"&ZONE=%s", Zone);
156 #endif /* USE_SRVLOC */
158 #include "afp_zeroconf.h"
159 #endif /* USE_ZEROCONF */
161 static void dsi_cleanup(const AFPConfig *config)
165 SLPError callbackerr;
167 DSI *dsi = (DSI *)config->obj.handle;
169 /* Do nothing if we didn't register. */
170 if (!dsi || dsi->srvloc_url[0] == '\0')
173 err = SLPOpen("en", SLP_FALSE, &hslp);
175 LOG(log_error, logtype_afpd, "dsi_cleanup: Error opening SRVLOC handle");
176 goto srvloc_dereg_err;
184 LOG(log_error, logtype_afpd, "dsi_cleanup: Error unregistering %s from SRVLOC", dsi->srvloc_url);
185 goto srvloc_dereg_err;
188 if (callbackerr != SLP_OK) {
189 LOG(log_error, logtype_afpd, "dsi_cleanup: Error in callback while trying to unregister %s from SRVLOC (%d)", dsi->srvloc_url, callbackerr);
190 goto srvloc_dereg_err;
194 dsi->srvloc_url[0] = '\0';
196 #elif defined (USE_ZEROCONF)
197 DSI *dsi = (DSI *)config->obj.handle;
199 /* Do nothing if we didn't register. */
200 if (!dsi || dsi->zeroconf_registered == 0)
203 zeroconf_deregister();
204 #endif /* USE_SRVLOC */
208 static void asp_cleanup(const AFPConfig *config)
210 /* we need to stop tickle handler */
212 nbp_unrgstr(config->obj.Obj, config->obj.Type, config->obj.Zone,
213 &config->obj.options.ddpaddr);
216 /* these two are almost identical. it should be possible to collapse them
217 * into one with minimal junk. */
218 static int asp_start(AFPConfig *config, AFPConfig *configs,
219 server_child *server_children)
223 if (!(asp = asp_getsession(config->obj.handle, server_children,
224 config->obj.options.tickleval))) {
225 LOG(log_error, logtype_afpd, "main: asp_getsession: %s", strerror(errno) );
226 exit( EXITERR_CLNT );
230 configfree(configs, config); /* free a bunch of stuff */
231 afp_over_asp(&config->obj);
237 #endif /* no afp/asp */
239 static int dsi_start(AFPConfig *config, AFPConfig *configs,
240 server_child *server_children)
244 if (!(dsi = dsi_getsession(config->obj.handle, server_children,
245 config->obj.options.tickleval))) {
246 LOG(log_error, logtype_afpd, "main: dsi_getsession: %s", strerror(errno) );
247 exit( EXITERR_CLNT );
252 configfree(configs, config);
253 afp_over_dsi(&config->obj); /* start a session */
261 static AFPConfig *ASPConfigInit(const struct afp_options *options,
262 unsigned char *refcount)
267 char *Obj, *Type = "AFPServer", *Zone = "*";
268 char *convname = NULL;
270 if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL)
273 if ((atp = atp_open(ATADDR_ANYPORT, &options->ddpaddr)) == NULL) {
274 LOG(log_error, logtype_afpd, "main: atp_open: %s", strerror(errno) );
279 if ((asp = asp_init( atp )) == NULL) {
280 LOG(log_error, logtype_afpd, "main: asp_init: %s", strerror(errno) );
286 /* register asp server */
287 Obj = (char *) options->hostname;
288 if (options->server && (size_t)-1 ==(convert_string_allocate( options->unixcharset, options->maccharset,
289 options->server, strlen(options->server), &convname)) ) {
290 if ((convname = strdup(options->server)) == NULL ) {
291 LOG(log_error, logtype_afpd, "malloc: %s", strerror(errno) );
292 goto serv_free_return;
296 if (nbp_name(convname, &Obj, &Type, &Zone )) {
297 LOG(log_error, logtype_afpd, "main: can't parse %s", options->server );
298 goto serv_free_return;
303 /* dup Obj, Type and Zone as they get assigned to a single internal
304 * buffer by nbp_name */
305 if ((config->obj.Obj = strdup(Obj)) == NULL)
306 goto serv_free_return;
308 if ((config->obj.Type = strdup(Type)) == NULL) {
309 free(config->obj.Obj);
310 goto serv_free_return;
313 if ((config->obj.Zone = strdup(Zone)) == NULL) {
314 free(config->obj.Obj);
315 free(config->obj.Type);
316 goto serv_free_return;
319 /* make sure we're not registered */
320 nbp_unrgstr(Obj, Type, Zone, &options->ddpaddr);
321 if (nbp_rgstr( atp_sockaddr( atp ), Obj, Type, Zone ) < 0 ) {
322 LOG(log_error, logtype_afpd, "Can't register %s:%s@%s", Obj, Type, Zone );
323 free(config->obj.Obj);
324 free(config->obj.Type);
325 free(config->obj.Zone);
326 goto serv_free_return;
329 LOG(log_info, logtype_afpd, "%s:%s@%s started on %u.%u:%u (%s)", Obj, Type, Zone,
330 ntohs( atp_sockaddr( atp )->sat_addr.s_net ),
331 atp_sockaddr( atp )->sat_addr.s_node,
332 atp_sockaddr( atp )->sat_port, VERSION );
334 config->fd = atp_fileno(atp);
335 config->obj.handle = asp;
336 config->obj.config = config;
337 config->obj.proto = AFPPROTO_ASP;
339 memcpy(&config->obj.options, options, sizeof(struct afp_options));
340 config->optcount = refcount;
343 config->server_start = asp_start;
344 config->server_cleanup = asp_cleanup;
353 #endif /* no afp/asp */
356 static AFPConfig *DSIConfigInit(const struct afp_options *options,
357 unsigned char *refcount,
358 const dsi_proto protocol)
364 if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL) {
365 LOG(log_error, logtype_afpd, "DSIConfigInit: malloc(config): %s", strerror(errno) );
369 LOG(log_debug, logtype_afpd, "DSIConfigInit: hostname: %s, ip/port: %s/%s, ",
371 options->ipaddr ? options->ipaddr : "default",
372 options->port ? options->port : "548");
374 if ((dsi = dsi_init(protocol, "afpd", options->hostname,
375 options->ipaddr, options->port,
376 options->flags & OPTION_PROXY,
377 options->server_quantum)) == NULL) {
378 LOG(log_error, logtype_afpd, "main: dsi_init: %s", strerror(errno) );
383 if (options->flags & OPTION_PROXY) {
384 LOG(log_info, logtype_afpd, "AFP/TCP proxy initialized for %s:%d (%s)",
385 getip_string((struct sockaddr *)&dsi->server), getip_port((struct sockaddr *)&dsi->server), VERSION);
387 LOG(log_info, logtype_afpd, "AFP/TCP started, advertising %s:%d (%s)",
388 getip_string((struct sockaddr *)&dsi->server), getip_port((struct sockaddr *)&dsi->server), VERSION);
392 dsi->srvloc_url[0] = '\0'; /* Mark that we haven't registered. */
393 if (!(options->flags & OPTION_NOSLP)) {
395 SLPError callbackerr;
397 unsigned int afp_port;
399 char *srvloc_hostname;
400 const char *hostname;
402 err = SLPOpen("en", SLP_FALSE, &hslp);
404 LOG(log_error, logtype_afpd, "DSIConfigInit: Error opening SRVLOC handle");
408 /* XXX We don't want to tack on the port number if we don't have to.
410 * Well, this seems to break MacOS < 10. If the user _really_ wants to
411 * use a non-default port, they can, but be aware, this server might
412 * not show up int the Network Browser.
414 afp_port = getip_port((struct sockaddr *)&dsi->server);
415 /* If specified use the FQDN to register with srvloc, otherwise use IP. */
418 hostname = options->fqdn;
419 p = strchr(hostname, ':');
422 hostname = getip_string((struct sockaddr *)&dsi->server);
424 srvloc_hostname = srvloc_encode(options, (options->server ? options->server : options->hostname));
426 if ((p) || afp_port == 548) {
427 l = snprintf(dsi->srvloc_url, sizeof(dsi->srvloc_url), "afp://%s/?NAME=%s", hostname, srvloc_hostname);
430 l = snprintf(dsi->srvloc_url, sizeof(dsi->srvloc_url), "afp://%s:%d/?NAME=%s", hostname, afp_port, srvloc_hostname);
433 if (l == -1 || l >= (int)sizeof(dsi->srvloc_url)) {
434 LOG(log_error, logtype_afpd, "DSIConfigInit: Hostname is too long for SRVLOC");
435 dsi->srvloc_url[0] = '\0';
441 SLP_LIFETIME_MAXIMUM,
448 LOG(log_error, logtype_afpd, "DSIConfigInit: Error registering %s with SRVLOC", dsi->srvloc_url);
449 dsi->srvloc_url[0] = '\0';
453 if (callbackerr != SLP_OK) {
454 LOG(log_error, logtype_afpd, "DSIConfigInit: Error in callback trying to register %s with SRVLOC", dsi->srvloc_url);
455 dsi->srvloc_url[0] = '\0';
459 LOG(log_info, logtype_afpd, "Sucessfully registered %s with SRVLOC", dsi->srvloc_url);
460 config->server_cleanup = dsi_cleanup;
465 #endif /* USE_SRVLOC */
468 dsi->zeroconf_registered = 0; /* Mark that we haven't registered. */
469 if (!(options->flags & OPTION_NOZEROCONF)) {
470 zeroconf_register(getip_port((struct sockaddr *)&dsi->server),
471 options->server ? options->server : options->hostname);
472 dsi->zeroconf_registered = 1; /* Mark that we have registered. */
473 config->server_cleanup = dsi_cleanup;
475 #endif /* USE_ZEROCONF */
477 config->fd = dsi->serversock;
478 config->obj.handle = dsi;
479 config->obj.config = config;
480 config->obj.proto = AFPPROTO_DSI;
482 memcpy(&config->obj.options, options, sizeof(struct afp_options));
483 /* get rid of any appletalk info. we use the fact that the DSI
484 * stuff is done after the ASP stuff. */
485 p = config->obj.options.server;
486 if (p && (q = strchr(p, ':')))
489 config->optcount = refcount;
492 config->server_start = dsi_start;
496 /* allocate server configurations. this should really store the last
497 * entry in config->last or something like that. that would make
498 * supporting multiple dsi transports easier. */
499 static AFPConfig *AFPConfigInit(const struct afp_options *options,
500 const struct afp_options *defoptions)
502 AFPConfig *config = NULL, *next = NULL;
503 unsigned char *refcount;
505 if ((refcount = (unsigned char *)
506 calloc(1, sizeof(unsigned char))) == NULL) {
507 LOG(log_error, logtype_afpd, "AFPConfigInit: calloc(refcount): %s", strerror(errno) );
512 /* handle asp transports */
513 if ((options->transports & AFPTRANS_DDP) &&
514 (config = ASPConfigInit(options, refcount)))
515 config->defoptions = defoptions;
520 set_signature(options);
522 /* handle dsi transports and dsi proxies. we only proxy
523 * for DSI connections. */
525 /* this should have something like the following:
526 * for (i=mindsi; i < maxdsi; i++)
527 * if (options->transports & (1 << i) &&
528 * (next = DSIConfigInit(options, refcount, i)))
529 * next->defoptions = defoptions;
531 if ((options->transports & AFPTRANS_TCP) &&
532 (((options->flags & OPTION_PROXY) == 0) ||
533 ((options->flags & OPTION_PROXY) && config))
534 && (next = DSIConfigInit(options, refcount, DSI_TCPIP)))
535 next->defoptions = defoptions;
537 /* load in all the authentication modules. we can load the same
538 things multiple times if necessary. however, loading different
539 things with the same names will cause complaints. by not loading
540 in any uams with proxies, we prevent ddp connections from succeeding.
542 auth_load(options->uampath, options->uamlist);
544 /* this should be able to accept multiple dsi transports. i think
545 * the only thing that gets affected is the net addresses. */
546 status_init(config, next, options);
548 /* attach dsi config to tail of asp config */
557 /* fill in the appropriate bits for each interface */
558 AFPConfig *configinit(struct afp_options *cmdline)
561 char buf[LINESIZE + 1], *p, have_option = 0;
563 struct afp_options options;
564 AFPConfig *config=NULL, *first = NULL;
567 /* Parse afp_ldap.conf first so we can set the uuid option */
568 acl_ldap_readconfig(_PATH_ACL_LDAPCONF);
569 #endif /* HAVE_ACLS */
571 /* if config file doesn't exist, load defaults */
572 if ((fp = fopen(cmdline->configfile, "r")) == NULL)
574 LOG(log_debug, logtype_afpd, "ConfigFile %s not found, assuming defaults",
575 cmdline->configfile);
576 return AFPConfigInit(cmdline, cmdline);
579 /* scan in the configuration file */
582 if (!fgets(&buf[len], LINESIZE - len, fp) || buf[len] == '#')
585 if ( len >= 2 && buf[len-2] == '\\' ) {
591 /* a little pre-processing to get rid of spaces and end-of-lines */
593 while (p && isspace(*p))
595 if (!p || (*p == '\0'))
600 memcpy(&options, cmdline, sizeof(options));
601 if (!afp_options_parseline(p, &options))
605 /* Enable UUID support if LDAP config is complete */
606 if (ldap_config_valid) {
607 LOG(log_info, logtype_afpd, "Enabling UUID support");
608 options.flags |= OPTION_UUID;
610 #endif /* HAVE_ACLS */
612 /* this should really get a head and a tail to simplify things. */
614 if ((first = AFPConfigInit(&options, cmdline)))
615 config = first->next ? first->next : first;
616 } else if ((config->next = AFPConfigInit(&options, cmdline))) {
617 config = config->next->next ? config->next->next : config->next;
621 LOG(log_debug, logtype_afpd, "Finished parsing Config File");
625 first = AFPConfigInit(cmdline, cmdline);