2 * $Id: afp_config.c,v 1.7 2001-09-23 18:47:52 jmarcus Exp $
4 * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
5 * All Rights Reserved. See COPYRIGHT.
10 #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 */
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
40 #include <atalk/dsi.h>
41 #include <atalk/atp.h>
42 #include <atalk/asp.h>
43 #include <atalk/nbp.h>
44 #include <atalk/afp.h>
45 #include <atalk/compat.h>
46 #include <atalk/server_child.h>
49 static char srvloc_url[512];
50 #endif /* USE_SRVLOC */
53 #include "afp_config.h"
59 /* get rid of unneeded configurations. i use reference counts to deal
60 * w/ multiple configs sharing the same afp_options. oh, to dream of
61 * garbage collection ... */
62 void configfree(AFPConfig *configs, const AFPConfig *config)
66 for (p = configs; p; p = q) {
71 /* do a little reference counting */
72 if (--(*p->optcount) < 1) {
73 afp_options_free(&p->obj.options, p->defoptions);
77 switch (p->obj.proto) {
83 atp_close(((ASP) p->obj.handle)->asp_atp);
86 #endif /* no afp/asp */
97 static void SRVLOC_callback(SLPHandle hslp, SLPError errcode, void *cookie) {
98 *(SLPError*)cookie = errcode;
100 #endif /* USE_SRVLOC */
103 static void dsi_cleanup(const AFPConfig *config)
106 SLPError callbackerr;
108 err = SLPOpen("en", SLP_FALSE, &hslp);
110 syslog(LOG_ERR, "Error opening SRVLOC handle");
111 goto srvloc_dereg_err;
119 syslog(LOG_ERR, "Error unregistering %s from SRVLOC", srvloc_url);
120 goto srvloc_dereg_err;
123 if (callbackerr != SLP_OK) {
124 syslog(LOG_ERR, "Error in callback while trying to unregister %s from SRVLOC (%i)", srvloc_url, callbackerr);
125 goto srvloc_dereg_err;
131 #endif /* USE_SRVLOC */
134 static void asp_cleanup(const AFPConfig *config)
136 nbp_unrgstr(config->obj.Obj, config->obj.Type, config->obj.Zone,
137 &config->obj.options.ddpaddr);
140 /* these two are almost identical. it should be possible to collapse them
141 * into one with minimal junk. */
142 static int asp_start(AFPConfig *config, AFPConfig *configs,
143 server_child *server_children)
147 if (!(asp = asp_getsession(config->obj.handle, server_children,
148 config->obj.options.tickleval))) {
149 syslog( LOG_ERR, "main: asp_getsession: %m" );
154 configfree(configs, config); /* free a bunch of stuff */
155 afp_over_asp(&config->obj);
161 #endif /* no afp/asp */
163 static int dsi_start(AFPConfig *config, AFPConfig *configs,
164 server_child *server_children)
168 if (!(dsi = dsi_getsession(config->obj.handle, server_children,
169 config->obj.options.tickleval))) {
170 syslog( LOG_ERR, "main: dsi_getsession: %m" );
176 configfree(configs, config);
177 afp_over_dsi(&config->obj); /* start a session */
185 static AFPConfig *ASPConfigInit(const struct afp_options *options,
186 unsigned char *refcount)
191 char *Obj, *Type = "AFPServer", *Zone = "*";
193 if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL)
196 if ((atp = atp_open(ATADDR_ANYPORT, &options->ddpaddr)) == NULL) {
197 syslog( LOG_ERR, "main: atp_open: %m");
202 if ((asp = asp_init( atp )) == NULL) {
203 syslog( LOG_ERR, "main: asp_init: %m" );
209 /* register asp server */
210 Obj = (char *) options->hostname;
211 if (nbp_name(options->server, &Obj, &Type, &Zone )) {
212 syslog( LOG_ERR, "main: can't parse %s", options->server );
213 goto serv_free_return;
216 /* dup Obj, Type and Zone as they get assigned to a single internal
217 * buffer by nbp_name */
218 if ((config->obj.Obj = strdup(Obj)) == NULL)
219 goto serv_free_return;
221 if ((config->obj.Type = strdup(Type)) == NULL) {
222 free(config->obj.Obj);
223 goto serv_free_return;
226 if ((config->obj.Zone = strdup(Zone)) == NULL) {
227 free(config->obj.Obj);
228 free(config->obj.Type);
229 goto serv_free_return;
232 /* make sure we're not registered */
233 nbp_unrgstr(Obj, Type, Zone, &options->ddpaddr);
234 if (nbp_rgstr( atp_sockaddr( atp ), Obj, Type, Zone ) < 0 ) {
235 syslog( LOG_ERR, "Can't register %s:%s@%s", Obj, Type, Zone );
236 free(config->obj.Obj);
237 free(config->obj.Type);
238 free(config->obj.Zone);
239 goto serv_free_return;
242 syslog( LOG_INFO, "%s:%s@%s started on %u.%u:%u (%s)", Obj, Type, Zone,
243 ntohs( atp_sockaddr( atp )->sat_addr.s_net ),
244 atp_sockaddr( atp )->sat_addr.s_node,
245 atp_sockaddr( atp )->sat_port, VERSION );
247 config->fd = atp_fileno(atp);
248 config->obj.handle = asp;
249 config->obj.config = config;
250 config->obj.proto = AFPPROTO_ASP;
252 memcpy(&config->obj.options, options, sizeof(struct afp_options));
253 config->optcount = refcount;
256 config->server_start = asp_start;
257 config->server_cleanup = asp_cleanup;
266 #endif /* no afp/asp */
269 static AFPConfig *DSIConfigInit(const struct afp_options *options,
270 unsigned char *refcount,
271 const dsi_proto protocol)
278 SLPError callbackerr;
280 struct servent *afpovertcp;
281 #endif /* USE_SRVLOC */
283 if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL) {
284 syslog( LOG_ERR, "DSIConfigInit: malloc(config): %m" );
288 if ((dsi = dsi_init(protocol, "afpd", options->hostname,
289 options->ipaddr, options->port,
290 options->flags & OPTION_PROXY,
291 options->server_quantum)) == NULL) {
292 syslog( LOG_ERR, "main: dsi_init: %m" );
297 if (options->flags & OPTION_PROXY) {
298 syslog(LOG_INFO, "ASIP proxy initialized for %s:%d (%s)",
299 inet_ntoa(dsi->server.sin_addr), ntohs(dsi->server.sin_port),
302 syslog(LOG_INFO, "ASIP started on %s:%d(%d) (%s)",
303 inet_ntoa(dsi->server.sin_addr), ntohs(dsi->server.sin_port),
304 dsi->serversock, VERSION);
308 err = SLPOpen("en", SLP_FALSE, &hslp);
310 syslog(LOG_ERR, "Error opening SRVLOC handle");
314 /* XXX We don't want to tack on the port number if we don't have to. Why?
315 * Well, this seems to break MacOS < 10. If the user _really_ wants to
316 * use a non-default port, they can, but be aware, this server might not
317 * show up int the Network Browser. */
318 afpovertcp = getservbyname("afpovertcp", "tcp");
319 if (dsi->server.sin_port == afpovertcp->s_port) {
320 snprintf(srvloc_url, sizeof(srvloc_url), "afp://%s/?NAME=%s", inet_ntoa(dsi->server.sin_addr), options->hostname);
323 snprintf(srvloc_url, sizeof(srvloc_url), "afp://%s:%d/?NAME=%s", inet_ntoa(dsi->server.sin_addr), ntohs(dsi->server.sin_port), options->hostname);
328 SLP_LIFETIME_MAXIMUM,
335 syslog(LOG_ERR, "Error registering %s with SRVLOC", srvloc_url);
339 if (callbackerr != SLP_OK) {
340 syslog(LOG_ERR, "Error in callback trying to register %s with SRVLOC", srvloc_url);
344 syslog(LOG_INFO, "Sucessfully registered %s with SRVLOC", srvloc_url);
348 #endif /* USE_SRVLOC */
351 config->fd = dsi->serversock;
352 config->obj.handle = dsi;
353 config->obj.config = config;
354 config->obj.proto = AFPPROTO_DSI;
356 memcpy(&config->obj.options, options, sizeof(struct afp_options));
357 /* get rid of any appletalk info. we use the fact that the DSI
358 * stuff is done after the ASP stuff. */
359 p = config->obj.options.server;
360 if (p && (q = strchr(p, ':')))
363 config->optcount = refcount;
366 config->server_start = dsi_start;
368 config->server_cleanup = dsi_cleanup;
369 #endif /* USE_SRVLOC */
373 /* allocate server configurations. this should really store the last
374 * entry in config->last or something like that. that would make
375 * supporting multiple dsi transports easier. */
376 static AFPConfig *AFPConfigInit(const struct afp_options *options,
377 const struct afp_options *defoptions)
379 AFPConfig *config = NULL, *next = NULL;
380 unsigned char *refcount;
382 if ((refcount = (unsigned char *)
383 calloc(1, sizeof(unsigned char))) == NULL) {
384 syslog( LOG_ERR, "AFPConfigInit: calloc(refcount): %m" );
389 /* handle asp transports */
390 if ((options->transports & AFPTRANS_DDP) &&
391 (config = ASPConfigInit(options, refcount)))
392 config->defoptions = defoptions;
395 /* handle dsi transports and dsi proxies. we only proxy
396 * for DSI connections. */
398 /* this should have something like the following:
399 * for (i=mindsi; i < maxdsi; i++)
400 * if (options->transports & (1 << i) &&
401 * (next = DSIConfigInit(options, refcount, i)))
402 * next->defoptions = defoptions;
404 if ((options->transports & AFPTRANS_TCP) &&
405 (((options->flags & OPTION_PROXY) == 0) ||
406 ((options->flags & OPTION_PROXY) && config))
407 && (next = DSIConfigInit(options, refcount, DSI_TCPIP)))
408 next->defoptions = defoptions;
410 /* load in all the authentication modules. we can load the same
411 things multiple times if necessary. however, loading different
412 things with the same names will cause complaints. by not loading
413 in any uams with proxies, we prevent ddp connections from succeeding.
415 auth_load(options->uampath, options->uamlist);
417 /* this should be able to accept multiple dsi transports. i think
418 * the only thing that gets affected is the net addresses. */
419 status_init(config, next, options);
421 /* attach dsi config to tail of asp config */
430 /* fill in the appropriate bits for each interface */
431 AFPConfig *configinit(struct afp_options *cmdline)
434 char buf[LINESIZE + 1], *p, have_option = 0;
435 struct afp_options options;
436 AFPConfig *config, *first = NULL;
438 /* if config file doesn't exist, load defaults */
439 if ((fp = fopen(cmdline->configfile, "r")) == NULL)
440 return AFPConfigInit(cmdline, cmdline);
442 /* scan in the configuration file */
444 if (!fgets(buf, sizeof(buf), fp) || buf[0] == '#')
447 /* a little pre-processing to get rid of spaces and end-of-lines */
449 while (p && isspace(*p))
451 if (!p || (*p == '\0'))
456 memcpy(&options, cmdline, sizeof(options));
457 if (!afp_options_parseline(p, &options))
460 /* this should really get a head and a tail to simplify things. */
462 if ((first = AFPConfigInit(&options, cmdline)))
463 config = first->next ? first->next : first;
464 } else if ((config->next = AFPConfigInit(&options, cmdline))) {
465 config = config->next->next ? config->next->next : config->next;
472 return AFPConfigInit(cmdline, cmdline);