2 * $Id: afp_config.c,v 1.21 2002-09-12 17:33:03 srittau 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;
290 #endif /* USE_SRVLOC */
292 if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL) {
293 LOG(log_error, logtype_afpd, "DSIConfigInit: malloc(config): %s", strerror(errno) );
297 if ((dsi = dsi_init(protocol, "afpd", options->hostname,
298 options->ipaddr, options->port,
299 options->flags & OPTION_PROXY,
300 options->server_quantum)) == NULL) {
301 LOG(log_error, logtype_afpd, "main: dsi_init: %s", strerror(errno) );
306 if (options->flags & OPTION_PROXY) {
307 LOG(log_info, logtype_afpd, "ASIP proxy initialized for %s:%d (%s)",
308 inet_ntoa(dsi->server.sin_addr), ntohs(dsi->server.sin_port),
311 LOG(log_info, logtype_afpd, "ASIP started on %s:%d(%d) (%s)",
312 inet_ntoa(dsi->server.sin_addr), ntohs(dsi->server.sin_port),
313 dsi->serversock, VERSION);
317 srvloc_url[0] = '\0'; /* Mark that we haven't registered. */
318 if (!(options->flags & OPTION_NOSLP)) {
319 err = SLPOpen("en", SLP_FALSE, &hslp);
321 LOG(log_error, logtype_afpd, "DSIConfigInit: Error opening SRVLOC handle");
325 /* XXX We don't want to tack on the port number if we don't have to.
327 * Well, this seems to break MacOS < 10. If the user _really_ wants to
328 * use a non-default port, they can, but be aware, this server might
329 * not show up int the Network Browser.
331 afpovertcp = getservbyname("afpovertcp", "tcp");
332 srvloc_hostname = (options->server ? options->server : options->hostname);
333 if (afpovertcp != NULL) {
334 afp_port = afpovertcp->s_port;
336 if (strlen(srvloc_hostname) > (sizeof(srvloc_url) - strlen(inet_ntoa(dsi->server.sin_addr)) - 21)) {
337 LOG(log_error, logtype_afpd, "DSIConfigInit: Hostname is too long for SRVLOC");
338 srvloc_url[0] = '\0';
341 if (dsi->server.sin_port == afp_port) {
342 sprintf(srvloc_url, "afp://%s/?NAME=%s", inet_ntoa(dsi->server.sin_addr), srvloc_hostname);
345 sprintf(srvloc_url, "afp://%s:%d/?NAME=%s", inet_ntoa(dsi->server.sin_addr), ntohs(dsi->server.sin_port), srvloc_hostname);
350 SLP_LIFETIME_MAXIMUM,
357 LOG(log_error, logtype_afpd, "DSIConfigInit: Error registering %s with SRVLOC", srvloc_url);
358 srvloc_url[0] = '\0';
362 if (callbackerr != SLP_OK) {
363 LOG(log_error, logtype_afpd, "DSIConfigInit: Error in callback trying to register %s with SRVLOC", srvloc_url);
364 srvloc_url[0] = '\0';
368 LOG(log_info, logtype_afpd, "Sucessfully registered %s with SRVLOC", srvloc_url);
373 #endif /* USE_SRVLOC */
376 config->fd = dsi->serversock;
377 config->obj.handle = dsi;
378 config->obj.config = config;
379 config->obj.proto = AFPPROTO_DSI;
381 memcpy(&config->obj.options, options, sizeof(struct afp_options));
382 /* get rid of any appletalk info. we use the fact that the DSI
383 * stuff is done after the ASP stuff. */
384 p = config->obj.options.server;
385 if (p && (q = strchr(p, ':')))
388 config->optcount = refcount;
391 config->server_start = dsi_start;
393 config->server_cleanup = dsi_cleanup;
394 #endif /* USE_SRVLOC */
398 /* allocate server configurations. this should really store the last
399 * entry in config->last or something like that. that would make
400 * supporting multiple dsi transports easier. */
401 static AFPConfig *AFPConfigInit(const struct afp_options *options,
402 const struct afp_options *defoptions)
404 AFPConfig *config = NULL, *next = NULL;
405 unsigned char *refcount;
407 if ((refcount = (unsigned char *)
408 calloc(1, sizeof(unsigned char))) == NULL) {
409 LOG(log_error, logtype_afpd, "AFPConfigInit: calloc(refcount): %s", strerror(errno) );
414 /* handle asp transports */
415 if ((options->transports & AFPTRANS_DDP) &&
416 (config = ASPConfigInit(options, refcount)))
417 config->defoptions = defoptions;
420 /* handle dsi transports and dsi proxies. we only proxy
421 * for DSI connections. */
423 /* this should have something like the following:
424 * for (i=mindsi; i < maxdsi; i++)
425 * if (options->transports & (1 << i) &&
426 * (next = DSIConfigInit(options, refcount, i)))
427 * next->defoptions = defoptions;
429 if ((options->transports & AFPTRANS_TCP) &&
430 (((options->flags & OPTION_PROXY) == 0) ||
431 ((options->flags & OPTION_PROXY) && config))
432 && (next = DSIConfigInit(options, refcount, DSI_TCPIP)))
433 next->defoptions = defoptions;
435 /* load in all the authentication modules. we can load the same
436 things multiple times if necessary. however, loading different
437 things with the same names will cause complaints. by not loading
438 in any uams with proxies, we prevent ddp connections from succeeding.
440 auth_load(options->uampath, options->uamlist);
442 /* this should be able to accept multiple dsi transports. i think
443 * the only thing that gets affected is the net addresses. */
444 status_init(config, next, options);
446 /* attach dsi config to tail of asp config */
455 /* fill in the appropriate bits for each interface */
456 AFPConfig *configinit(struct afp_options *cmdline)
459 char buf[LINESIZE + 1], *p, have_option = 0;
460 struct afp_options options;
461 AFPConfig *config, *first = NULL;
463 /* if config file doesn't exist, load defaults */
464 if ((fp = fopen(cmdline->configfile, "r")) == NULL)
466 LOG(log_debug, logtype_afpd, "ConfigFile %s not found, assuming defaults",
467 cmdline->configfile);
468 return AFPConfigInit(cmdline, cmdline);
471 LOG(log_debug, logtype_afpd, "Loading ConfigFile");
473 /* scan in the configuration file */
475 if (!fgets(buf, sizeof(buf), fp) || buf[0] == '#')
478 /* a little pre-processing to get rid of spaces and end-of-lines */
480 while (p && isspace(*p))
482 if (!p || (*p == '\0'))
487 memcpy(&options, cmdline, sizeof(options));
488 if (!afp_options_parseline(p, &options))
491 /* this should really get a head and a tail to simplify things. */
493 if ((first = AFPConfigInit(&options, cmdline)))
494 config = first->next ? first->next : first;
495 } else if ((config->next = AFPConfigInit(&options, cmdline))) {
496 config = config->next->next ? config->next->next : config->next;
500 LOG(log_debug, logtype_afpd, "Finished parsing Config File");
504 return AFPConfigInit(cmdline, cmdline);