2 * $Id: afp_config.c,v 1.17 2002-03-24 01:23:40 sibaz 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;
110 err = SLPOpen("en", SLP_FALSE, &hslp);
112 LOG(log_error, logtype_afpd, "dsi_cleanup: Error opening SRVLOC handle");
113 goto srvloc_dereg_err;
121 LOG(log_error, logtype_afpd, "dsi_cleanup: Error unregistering %s from SRVLOC", srvloc_url);
122 goto srvloc_dereg_err;
125 if (callbackerr != SLP_OK) {
126 LOG(log_error, logtype_afpd, "dsi_cleanup: Error in callback while trying to unregister %s from SRVLOC (%d)", srvloc_url, callbackerr);
127 goto srvloc_dereg_err;
133 #endif /* USE_SRVLOC */
136 static void asp_cleanup(const AFPConfig *config)
138 nbp_unrgstr(config->obj.Obj, config->obj.Type, config->obj.Zone,
139 &config->obj.options.ddpaddr);
142 /* these two are almost identical. it should be possible to collapse them
143 * into one with minimal junk. */
144 static int asp_start(AFPConfig *config, AFPConfig *configs,
145 server_child *server_children)
149 if (!(asp = asp_getsession(config->obj.handle, server_children,
150 config->obj.options.tickleval))) {
151 LOG(log_error, logtype_afpd, "main: asp_getsession: %s", strerror(errno) );
156 configfree(configs, config); /* free a bunch of stuff */
157 afp_over_asp(&config->obj);
163 #endif /* no afp/asp */
165 static int dsi_start(AFPConfig *config, AFPConfig *configs,
166 server_child *server_children)
170 if (!(dsi = dsi_getsession(config->obj.handle, server_children,
171 config->obj.options.tickleval))) {
172 LOG(log_error, logtype_afpd, "main: dsi_getsession: %s", strerror(errno) );
178 configfree(configs, config);
179 afp_over_dsi(&config->obj); /* start a session */
187 static AFPConfig *ASPConfigInit(const struct afp_options *options,
188 unsigned char *refcount)
193 char *Obj, *Type = "AFPServer", *Zone = "*";
195 if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL)
198 if ((atp = atp_open(ATADDR_ANYPORT, &options->ddpaddr)) == NULL) {
199 LOG(log_error, logtype_afpd, "main: atp_open: %s", strerror(errno) );
204 if ((asp = asp_init( atp )) == NULL) {
205 LOG(log_error, logtype_afpd, "main: asp_init: %s", strerror(errno) );
211 /* register asp server */
212 Obj = (char *) options->hostname;
213 if (nbp_name(options->server, &Obj, &Type, &Zone )) {
214 LOG(log_error, logtype_afpd, "main: can't parse %s", options->server );
215 goto serv_free_return;
218 /* dup Obj, Type and Zone as they get assigned to a single internal
219 * buffer by nbp_name */
220 if ((config->obj.Obj = strdup(Obj)) == NULL)
221 goto serv_free_return;
223 if ((config->obj.Type = strdup(Type)) == NULL) {
224 free(config->obj.Obj);
225 goto serv_free_return;
228 if ((config->obj.Zone = strdup(Zone)) == NULL) {
229 free(config->obj.Obj);
230 free(config->obj.Type);
231 goto serv_free_return;
234 /* make sure we're not registered */
235 nbp_unrgstr(Obj, Type, Zone, &options->ddpaddr);
236 if (nbp_rgstr( atp_sockaddr( atp ), Obj, Type, Zone ) < 0 ) {
237 LOG(log_error, logtype_afpd, "Can't register %s:%s@%s", Obj, Type, Zone );
238 free(config->obj.Obj);
239 free(config->obj.Type);
240 free(config->obj.Zone);
241 goto serv_free_return;
244 LOG(log_info, logtype_afpd, "%s:%s@%s started on %u.%u:%u (%s)", Obj, Type, Zone,
245 ntohs( atp_sockaddr( atp )->sat_addr.s_net ),
246 atp_sockaddr( atp )->sat_addr.s_node,
247 atp_sockaddr( atp )->sat_port, VERSION );
249 config->fd = atp_fileno(atp);
250 config->obj.handle = asp;
251 config->obj.config = config;
252 config->obj.proto = AFPPROTO_ASP;
254 memcpy(&config->obj.options, options, sizeof(struct afp_options));
255 config->optcount = refcount;
258 config->server_start = asp_start;
259 config->server_cleanup = asp_cleanup;
268 #endif /* no afp/asp */
271 static AFPConfig *DSIConfigInit(const struct afp_options *options,
272 unsigned char *refcount,
273 const dsi_proto protocol)
280 SLPError callbackerr;
282 struct servent *afpovertcp;
284 #endif /* USE_SRVLOC */
286 if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL) {
287 LOG(log_error, logtype_afpd, "DSIConfigInit: malloc(config): %s", strerror(errno) );
291 if ((dsi = dsi_init(protocol, "afpd", options->hostname,
292 options->ipaddr, options->port,
293 options->flags & OPTION_PROXY,
294 options->server_quantum)) == NULL) {
295 LOG(log_error, logtype_afpd, "main: dsi_init: %s", strerror(errno) );
300 if (options->flags & OPTION_PROXY) {
301 LOG(log_info, logtype_afpd, "ASIP proxy initialized for %s:%d (%s)",
302 inet_ntoa(dsi->server.sin_addr), ntohs(dsi->server.sin_port),
305 LOG(log_info, logtype_afpd, "ASIP started on %s:%d(%d) (%s)",
306 inet_ntoa(dsi->server.sin_addr), ntohs(dsi->server.sin_port),
307 dsi->serversock, VERSION);
311 err = SLPOpen("en", SLP_FALSE, &hslp);
313 LOG(log_error, logtype_afpd, "DSIConfigInit: Error opening SRVLOC handle");
317 /* XXX We don't want to tack on the port number if we don't have to. Why?
318 * Well, this seems to break MacOS < 10. If the user _really_ wants to
319 * use a non-default port, they can, but be aware, this server might not
320 * show up int the Network Browser. */
321 afpovertcp = getservbyname("afpovertcp", "tcp");
322 if (afpovertcp != NULL) {
323 afp_port = afpovertcp->s_port;
325 if (strlen(options->hostname) > (sizeof(srvloc_url) - strlen(inet_ntoa(dsi->server.sin_addr)) - 21)) {
326 LOG(log_error, logtype_afpd, "DSIConfigInit: Hostname is too long for SRVLOC");
329 if (dsi->server.sin_port == afp_port) {
330 sprintf(srvloc_url, "afp://%s/?NAME=%s", inet_ntoa(dsi->server.sin_addr), options->hostname);
333 sprintf(srvloc_url, "afp://%s:%d/?NAME=%s", inet_ntoa(dsi->server.sin_addr), ntohs(dsi->server.sin_port), options->hostname);
338 SLP_LIFETIME_MAXIMUM,
345 LOG(log_error, logtype_afpd, "DSIConfigInit: Error registering %s with SRVLOC", srvloc_url);
349 if (callbackerr != SLP_OK) {
350 LOG(log_error, logtype_afpd, "DSIConfigInit: Error in callback trying to register %s with SRVLOC", srvloc_url);
354 LOG(log_info, logtype_afpd, "Sucessfully registered %s with SRVLOC", srvloc_url);
358 #endif /* USE_SRVLOC */
361 config->fd = dsi->serversock;
362 config->obj.handle = dsi;
363 config->obj.config = config;
364 config->obj.proto = AFPPROTO_DSI;
366 memcpy(&config->obj.options, options, sizeof(struct afp_options));
367 /* get rid of any appletalk info. we use the fact that the DSI
368 * stuff is done after the ASP stuff. */
369 p = config->obj.options.server;
370 if (p && (q = strchr(p, ':')))
373 config->optcount = refcount;
376 config->server_start = dsi_start;
378 config->server_cleanup = dsi_cleanup;
379 #endif /* USE_SRVLOC */
383 /* allocate server configurations. this should really store the last
384 * entry in config->last or something like that. that would make
385 * supporting multiple dsi transports easier. */
386 static AFPConfig *AFPConfigInit(const struct afp_options *options,
387 const struct afp_options *defoptions)
389 AFPConfig *config = NULL, *next = NULL;
390 unsigned char *refcount;
392 if ((refcount = (unsigned char *)
393 calloc(1, sizeof(unsigned char))) == NULL) {
394 LOG(log_error, logtype_afpd, "AFPConfigInit: calloc(refcount): %s", strerror(errno) );
399 /* handle asp transports */
400 if ((options->transports & AFPTRANS_DDP) &&
401 (config = ASPConfigInit(options, refcount)))
402 config->defoptions = defoptions;
405 /* handle dsi transports and dsi proxies. we only proxy
406 * for DSI connections. */
408 /* this should have something like the following:
409 * for (i=mindsi; i < maxdsi; i++)
410 * if (options->transports & (1 << i) &&
411 * (next = DSIConfigInit(options, refcount, i)))
412 * next->defoptions = defoptions;
414 if ((options->transports & AFPTRANS_TCP) &&
415 (((options->flags & OPTION_PROXY) == 0) ||
416 ((options->flags & OPTION_PROXY) && config))
417 && (next = DSIConfigInit(options, refcount, DSI_TCPIP)))
418 next->defoptions = defoptions;
420 /* load in all the authentication modules. we can load the same
421 things multiple times if necessary. however, loading different
422 things with the same names will cause complaints. by not loading
423 in any uams with proxies, we prevent ddp connections from succeeding.
425 auth_load(options->uampath, options->uamlist);
427 /* this should be able to accept multiple dsi transports. i think
428 * the only thing that gets affected is the net addresses. */
429 status_init(config, next, options);
431 /* attach dsi config to tail of asp config */
440 /* fill in the appropriate bits for each interface */
441 AFPConfig *configinit(struct afp_options *cmdline)
444 char buf[LINESIZE + 1], *p, have_option = 0;
445 struct afp_options options;
446 AFPConfig *config, *first = NULL;
448 /* if config file doesn't exist, load defaults */
449 if ((fp = fopen(cmdline->configfile, "r")) == NULL)
450 return AFPConfigInit(cmdline, cmdline);
452 /* scan in the configuration file */
454 if (!fgets(buf, sizeof(buf), fp) || buf[0] == '#')
457 /* a little pre-processing to get rid of spaces and end-of-lines */
459 while (p && isspace(*p))
461 if (!p || (*p == '\0'))
466 memcpy(&options, cmdline, sizeof(options));
467 if (!afp_options_parseline(p, &options))
470 /* this should really get a head and a tail to simplify things. */
472 if ((first = AFPConfigInit(&options, cmdline)))
473 config = first->next ? first->next : first;
474 } else if ((config->next = AFPConfigInit(&options, cmdline))) {
475 config = config->next->next ? config->next->next : config->next;
482 return AFPConfigInit(cmdline, cmdline);