2 * $Id: afp_config.c,v 1.10 2001-12-15 06:25:44 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 */
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 syslog(LOG_ERR, "Error opening SRVLOC handle");
113 goto srvloc_dereg_err;
121 syslog(LOG_ERR, "Error unregistering %s from SRVLOC", srvloc_url);
122 goto srvloc_dereg_err;
125 if (callbackerr != SLP_OK) {
126 syslog(LOG_ERR, "Error in callback while trying to unregister %s from SRVLOC (%i)", 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 syslog( LOG_ERR, "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 syslog( LOG_ERR, "main: dsi_getsession: %s", strerror(errno) );
176 config->obj.handle = dsi;
180 configfree(configs, config);
181 afp_over_dsi(&config->obj); /* start a session */
189 static AFPConfig *ASPConfigInit(const struct afp_options *options,
190 unsigned char *refcount)
195 char *Obj, *Type = "AFPServer", *Zone = "*";
197 if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL)
200 if ((atp = atp_open(ATADDR_ANYPORT, &options->ddpaddr)) == NULL) {
201 syslog( LOG_ERR, "main: atp_open: %s", strerror(errno) );
206 if ((asp = asp_init( atp )) == NULL) {
207 syslog( LOG_ERR, "main: asp_init: %s", strerror(errno) );
213 /* register asp server */
214 Obj = (char *) options->hostname;
215 if (nbp_name(options->server, &Obj, &Type, &Zone )) {
216 syslog( LOG_ERR, "main: can't parse %s", options->server );
217 goto serv_free_return;
220 /* dup Obj, Type and Zone as they get assigned to a single internal
221 * buffer by nbp_name */
222 if ((config->obj.Obj = strdup(Obj)) == NULL)
223 goto serv_free_return;
225 if ((config->obj.Type = strdup(Type)) == NULL) {
226 free(config->obj.Obj);
227 goto serv_free_return;
230 if ((config->obj.Zone = strdup(Zone)) == NULL) {
231 free(config->obj.Obj);
232 free(config->obj.Type);
233 goto serv_free_return;
236 /* make sure we're not registered */
237 nbp_unrgstr(Obj, Type, Zone, &options->ddpaddr);
238 if (nbp_rgstr( atp_sockaddr( atp ), Obj, Type, Zone ) < 0 ) {
239 syslog( LOG_ERR, "Can't register %s:%s@%s", Obj, Type, Zone );
240 free(config->obj.Obj);
241 free(config->obj.Type);
242 free(config->obj.Zone);
243 goto serv_free_return;
246 syslog( LOG_INFO, "%s:%s@%s started on %u.%u:%u (%s)", Obj, Type, Zone,
247 ntohs( atp_sockaddr( atp )->sat_addr.s_net ),
248 atp_sockaddr( atp )->sat_addr.s_node,
249 atp_sockaddr( atp )->sat_port, VERSION );
251 config->fd = atp_fileno(atp);
252 config->obj.handle = asp;
253 config->obj.config = config;
254 config->obj.proto = AFPPROTO_ASP;
256 memcpy(&config->obj.options, options, sizeof(struct afp_options));
257 config->optcount = refcount;
260 config->server_start = asp_start;
261 config->server_cleanup = asp_cleanup;
270 #endif /* no afp/asp */
273 static AFPConfig *DSIConfigInit(const struct afp_options *options,
274 unsigned char *refcount,
275 const dsi_proto protocol)
282 SLPError callbackerr;
284 struct servent *afpovertcp;
285 #endif /* USE_SRVLOC */
287 if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL) {
288 syslog( LOG_ERR, "DSIConfigInit: malloc(config): %s", strerror(errno) );
292 if ((dsi = dsi_init(protocol, "afpd", options->hostname,
293 options->ipaddr, options->port,
294 options->flags & OPTION_PROXY,
295 options->server_quantum)) == NULL) {
296 syslog( LOG_ERR, "main: dsi_init: %s", strerror(errno) );
301 if (options->flags & OPTION_PROXY) {
302 syslog(LOG_INFO, "ASIP proxy initialized for %s:%d (%s)",
303 inet_ntoa(dsi->server.sin_addr), ntohs(dsi->server.sin_port),
306 syslog(LOG_INFO, "ASIP started on %s:%d(%d) (%s)",
307 inet_ntoa(dsi->server.sin_addr), ntohs(dsi->server.sin_port),
308 dsi->serversock, VERSION);
312 err = SLPOpen("en", SLP_FALSE, &hslp);
314 syslog(LOG_ERR, "Error opening SRVLOC handle");
318 /* XXX We don't want to tack on the port number if we don't have to. Why?
319 * Well, this seems to break MacOS < 10. If the user _really_ wants to
320 * use a non-default port, they can, but be aware, this server might not
321 * show up int the Network Browser. */
322 afpovertcp = getservbyname("afpovertcp", "tcp");
323 if (dsi->server.sin_port == afpovertcp->s_port) {
324 snprintf(srvloc_url, sizeof(srvloc_url), "afp://%s/?NAME=%s", inet_ntoa(dsi->server.sin_addr), options->hostname);
327 snprintf(srvloc_url, sizeof(srvloc_url), "afp://%s:%d/?NAME=%s", inet_ntoa(dsi->server.sin_addr), ntohs(dsi->server.sin_port), options->hostname);
332 SLP_LIFETIME_MAXIMUM,
339 syslog(LOG_ERR, "Error registering %s with SRVLOC", srvloc_url);
343 if (callbackerr != SLP_OK) {
344 syslog(LOG_ERR, "Error in callback trying to register %s with SRVLOC", srvloc_url);
348 syslog(LOG_INFO, "Sucessfully registered %s with SRVLOC", srvloc_url);
352 #endif /* USE_SRVLOC */
355 config->fd = dsi->serversock;
356 config->obj.handle = dsi;
357 config->obj.config = config;
358 config->obj.proto = AFPPROTO_DSI;
360 memcpy(&config->obj.options, options, sizeof(struct afp_options));
361 /* get rid of any appletalk info. we use the fact that the DSI
362 * stuff is done after the ASP stuff. */
363 p = config->obj.options.server;
364 if (p && (q = strchr(p, ':')))
367 config->optcount = refcount;
370 config->server_start = dsi_start;
372 config->server_cleanup = dsi_cleanup;
373 #endif /* USE_SRVLOC */
377 /* allocate server configurations. this should really store the last
378 * entry in config->last or something like that. that would make
379 * supporting multiple dsi transports easier. */
380 static AFPConfig *AFPConfigInit(const struct afp_options *options,
381 const struct afp_options *defoptions)
383 AFPConfig *config = NULL, *next = NULL;
384 unsigned char *refcount;
386 if ((refcount = (unsigned char *)
387 calloc(1, sizeof(unsigned char))) == NULL) {
388 syslog( LOG_ERR, "AFPConfigInit: calloc(refcount): %s", strerror(errno) );
393 /* handle asp transports */
394 if ((options->transports & AFPTRANS_DDP) &&
395 (config = ASPConfigInit(options, refcount)))
396 config->defoptions = defoptions;
399 /* handle dsi transports and dsi proxies. we only proxy
400 * for DSI connections. */
402 /* this should have something like the following:
403 * for (i=mindsi; i < maxdsi; i++)
404 * if (options->transports & (1 << i) &&
405 * (next = DSIConfigInit(options, refcount, i)))
406 * next->defoptions = defoptions;
408 if ((options->transports & AFPTRANS_TCP) &&
409 (((options->flags & OPTION_PROXY) == 0) ||
410 ((options->flags & OPTION_PROXY) && config))
411 && (next = DSIConfigInit(options, refcount, DSI_TCPIP)))
412 next->defoptions = defoptions;
414 /* load in all the authentication modules. we can load the same
415 things multiple times if necessary. however, loading different
416 things with the same names will cause complaints. by not loading
417 in any uams with proxies, we prevent ddp connections from succeeding.
419 auth_load(options->uampath, options->uamlist);
421 /* this should be able to accept multiple dsi transports. i think
422 * the only thing that gets affected is the net addresses. */
423 status_init(config, next, options);
425 /* attach dsi config to tail of asp config */
434 /* fill in the appropriate bits for each interface */
435 AFPConfig *configinit(struct afp_options *cmdline)
438 char buf[LINESIZE + 1], *p, have_option = 0;
439 struct afp_options options;
440 AFPConfig *config, *first = NULL;
442 /* if config file doesn't exist, load defaults */
443 if ((fp = fopen(cmdline->configfile, "r")) == NULL)
444 return AFPConfigInit(cmdline, cmdline);
446 /* scan in the configuration file */
448 if (!fgets(buf, sizeof(buf), fp) || buf[0] == '#')
451 /* a little pre-processing to get rid of spaces and end-of-lines */
453 while (p && isspace(*p))
455 if (!p || (*p == '\0'))
460 memcpy(&options, cmdline, sizeof(options));
461 if (!afp_options_parseline(p, &options))
464 /* this should really get a head and a tail to simplify things. */
466 if ((first = AFPConfigInit(&options, cmdline)))
467 config = first->next ? first->next : first;
468 } else if ((config->next = AFPConfigInit(&options, cmdline))) {
469 config = config->next->next ? config->next->next : config->next;
476 return AFPConfigInit(cmdline, cmdline);