2 * $Id: afp_config.c,v 1.9 2001-12-10 20:16:53 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 */
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) );
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 syslog( LOG_ERR, "main: atp_open: %s", strerror(errno) );
204 if ((asp = asp_init( atp )) == NULL) {
205 syslog( LOG_ERR, "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 syslog( LOG_ERR, "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 syslog( LOG_ERR, "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 syslog( LOG_INFO, "%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;
283 #endif /* USE_SRVLOC */
285 if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL) {
286 syslog( LOG_ERR, "DSIConfigInit: malloc(config): %s", strerror(errno) );
290 if ((dsi = dsi_init(protocol, "afpd", options->hostname,
291 options->ipaddr, options->port,
292 options->flags & OPTION_PROXY,
293 options->server_quantum)) == NULL) {
294 syslog( LOG_ERR, "main: dsi_init: %s", strerror(errno) );
299 if (options->flags & OPTION_PROXY) {
300 syslog(LOG_INFO, "ASIP proxy initialized for %s:%d (%s)",
301 inet_ntoa(dsi->server.sin_addr), ntohs(dsi->server.sin_port),
304 syslog(LOG_INFO, "ASIP started on %s:%d(%d) (%s)",
305 inet_ntoa(dsi->server.sin_addr), ntohs(dsi->server.sin_port),
306 dsi->serversock, VERSION);
310 err = SLPOpen("en", SLP_FALSE, &hslp);
312 syslog(LOG_ERR, "Error opening SRVLOC handle");
316 /* XXX We don't want to tack on the port number if we don't have to. Why?
317 * Well, this seems to break MacOS < 10. If the user _really_ wants to
318 * use a non-default port, they can, but be aware, this server might not
319 * show up int the Network Browser. */
320 afpovertcp = getservbyname("afpovertcp", "tcp");
321 if (dsi->server.sin_port == afpovertcp->s_port) {
322 snprintf(srvloc_url, sizeof(srvloc_url), "afp://%s/?NAME=%s", inet_ntoa(dsi->server.sin_addr), options->hostname);
325 snprintf(srvloc_url, sizeof(srvloc_url), "afp://%s:%d/?NAME=%s", inet_ntoa(dsi->server.sin_addr), ntohs(dsi->server.sin_port), options->hostname);
330 SLP_LIFETIME_MAXIMUM,
337 syslog(LOG_ERR, "Error registering %s with SRVLOC", srvloc_url);
341 if (callbackerr != SLP_OK) {
342 syslog(LOG_ERR, "Error in callback trying to register %s with SRVLOC", srvloc_url);
346 syslog(LOG_INFO, "Sucessfully registered %s with SRVLOC", srvloc_url);
350 #endif /* USE_SRVLOC */
353 config->fd = dsi->serversock;
354 config->obj.handle = dsi;
355 config->obj.config = config;
356 config->obj.proto = AFPPROTO_DSI;
358 memcpy(&config->obj.options, options, sizeof(struct afp_options));
359 /* get rid of any appletalk info. we use the fact that the DSI
360 * stuff is done after the ASP stuff. */
361 p = config->obj.options.server;
362 if (p && (q = strchr(p, ':')))
365 config->optcount = refcount;
368 config->server_start = dsi_start;
370 config->server_cleanup = dsi_cleanup;
371 #endif /* USE_SRVLOC */
375 /* allocate server configurations. this should really store the last
376 * entry in config->last or something like that. that would make
377 * supporting multiple dsi transports easier. */
378 static AFPConfig *AFPConfigInit(const struct afp_options *options,
379 const struct afp_options *defoptions)
381 AFPConfig *config = NULL, *next = NULL;
382 unsigned char *refcount;
384 if ((refcount = (unsigned char *)
385 calloc(1, sizeof(unsigned char))) == NULL) {
386 syslog( LOG_ERR, "AFPConfigInit: calloc(refcount): %s", strerror(errno) );
391 /* handle asp transports */
392 if ((options->transports & AFPTRANS_DDP) &&
393 (config = ASPConfigInit(options, refcount)))
394 config->defoptions = defoptions;
397 /* handle dsi transports and dsi proxies. we only proxy
398 * for DSI connections. */
400 /* this should have something like the following:
401 * for (i=mindsi; i < maxdsi; i++)
402 * if (options->transports & (1 << i) &&
403 * (next = DSIConfigInit(options, refcount, i)))
404 * next->defoptions = defoptions;
406 if ((options->transports & AFPTRANS_TCP) &&
407 (((options->flags & OPTION_PROXY) == 0) ||
408 ((options->flags & OPTION_PROXY) && config))
409 && (next = DSIConfigInit(options, refcount, DSI_TCPIP)))
410 next->defoptions = defoptions;
412 /* load in all the authentication modules. we can load the same
413 things multiple times if necessary. however, loading different
414 things with the same names will cause complaints. by not loading
415 in any uams with proxies, we prevent ddp connections from succeeding.
417 auth_load(options->uampath, options->uamlist);
419 /* this should be able to accept multiple dsi transports. i think
420 * the only thing that gets affected is the net addresses. */
421 status_init(config, next, options);
423 /* attach dsi config to tail of asp config */
432 /* fill in the appropriate bits for each interface */
433 AFPConfig *configinit(struct afp_options *cmdline)
436 char buf[LINESIZE + 1], *p, have_option = 0;
437 struct afp_options options;
438 AFPConfig *config, *first = NULL;
440 /* if config file doesn't exist, load defaults */
441 if ((fp = fopen(cmdline->configfile, "r")) == NULL)
442 return AFPConfigInit(cmdline, cmdline);
444 /* scan in the configuration file */
446 if (!fgets(buf, sizeof(buf), fp) || buf[0] == '#')
449 /* a little pre-processing to get rid of spaces and end-of-lines */
451 while (p && isspace(*p))
453 if (!p || (*p == '\0'))
458 memcpy(&options, cmdline, sizeof(options));
459 if (!afp_options_parseline(p, &options))
462 /* this should really get a head and a tail to simplify things. */
464 if ((first = AFPConfigInit(&options, cmdline)))
465 config = first->next ? first->next : first;
466 } else if ((config->next = AFPConfigInit(&options, cmdline))) {
467 config = config->next->next ? config->next->next : config->next;
474 return AFPConfigInit(cmdline, cmdline);