2 * $Id: afp_config.c,v 1.13 2001-12-16 19:45:17 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, "dsi_cleanup: Error opening SRVLOC handle");
113 goto srvloc_dereg_err;
121 syslog(LOG_ERR, "dsi_cleanup: Error unregistering %s from SRVLOC", srvloc_url);
122 goto srvloc_dereg_err;
125 if (callbackerr != SLP_OK) {
126 syslog(LOG_ERR, "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 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, "DSIConfigInit: 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 (strlen(options->hostname) > (sizeof(srvloc_url) - strlen(inet_ntoa(dsi->server.sin_addr)) - 21)) {
322 syslog(LOG_ERR, "DSIConfigInit: Hostname is too long for SRVLOC");
325 if (dsi->server.sin_port == afpovertcp->s_port) {
326 sprintf(srvloc_url, "afp://%s/?NAME=%s", inet_ntoa(dsi->server.sin_addr), options->hostname);
329 sprintf(srvloc_url, "afp://%s:%d/?NAME=%s", inet_ntoa(dsi->server.sin_addr), ntohs(dsi->server.sin_port), options->hostname);
334 SLP_LIFETIME_MAXIMUM,
341 syslog(LOG_ERR, "DSIConfigInit: Error registering %s with SRVLOC", srvloc_url);
345 if (callbackerr != SLP_OK) {
346 syslog(LOG_ERR, "DSIConfigInit: Error in callback trying to register %s with SRVLOC", srvloc_url);
350 syslog(LOG_INFO, "Sucessfully registered %s with SRVLOC", srvloc_url);
354 #endif /* USE_SRVLOC */
357 config->fd = dsi->serversock;
358 config->obj.handle = dsi;
359 config->obj.config = config;
360 config->obj.proto = AFPPROTO_DSI;
362 memcpy(&config->obj.options, options, sizeof(struct afp_options));
363 /* get rid of any appletalk info. we use the fact that the DSI
364 * stuff is done after the ASP stuff. */
365 p = config->obj.options.server;
366 if (p && (q = strchr(p, ':')))
369 config->optcount = refcount;
372 config->server_start = dsi_start;
374 config->server_cleanup = dsi_cleanup;
375 #endif /* USE_SRVLOC */
379 /* allocate server configurations. this should really store the last
380 * entry in config->last or something like that. that would make
381 * supporting multiple dsi transports easier. */
382 static AFPConfig *AFPConfigInit(const struct afp_options *options,
383 const struct afp_options *defoptions)
385 AFPConfig *config = NULL, *next = NULL;
386 unsigned char *refcount;
388 if ((refcount = (unsigned char *)
389 calloc(1, sizeof(unsigned char))) == NULL) {
390 syslog( LOG_ERR, "AFPConfigInit: calloc(refcount): %s", strerror(errno) );
395 /* handle asp transports */
396 if ((options->transports & AFPTRANS_DDP) &&
397 (config = ASPConfigInit(options, refcount)))
398 config->defoptions = defoptions;
401 /* handle dsi transports and dsi proxies. we only proxy
402 * for DSI connections. */
404 /* this should have something like the following:
405 * for (i=mindsi; i < maxdsi; i++)
406 * if (options->transports & (1 << i) &&
407 * (next = DSIConfigInit(options, refcount, i)))
408 * next->defoptions = defoptions;
410 if ((options->transports & AFPTRANS_TCP) &&
411 (((options->flags & OPTION_PROXY) == 0) ||
412 ((options->flags & OPTION_PROXY) && config))
413 && (next = DSIConfigInit(options, refcount, DSI_TCPIP)))
414 next->defoptions = defoptions;
416 /* load in all the authentication modules. we can load the same
417 things multiple times if necessary. however, loading different
418 things with the same names will cause complaints. by not loading
419 in any uams with proxies, we prevent ddp connections from succeeding.
421 auth_load(options->uampath, options->uamlist);
423 /* this should be able to accept multiple dsi transports. i think
424 * the only thing that gets affected is the net addresses. */
425 status_init(config, next, options);
427 /* attach dsi config to tail of asp config */
436 /* fill in the appropriate bits for each interface */
437 AFPConfig *configinit(struct afp_options *cmdline)
440 char buf[LINESIZE + 1], *p, have_option = 0;
441 struct afp_options options;
442 AFPConfig *config, *first = NULL;
444 /* if config file doesn't exist, load defaults */
445 if ((fp = fopen(cmdline->configfile, "r")) == NULL)
446 return AFPConfigInit(cmdline, cmdline);
448 /* scan in the configuration file */
450 if (!fgets(buf, sizeof(buf), fp) || buf[0] == '#')
453 /* a little pre-processing to get rid of spaces and end-of-lines */
455 while (p && isspace(*p))
457 if (!p || (*p == '\0'))
462 memcpy(&options, cmdline, sizeof(options));
463 if (!afp_options_parseline(p, &options))
466 /* this should really get a head and a tail to simplify things. */
468 if ((first = AFPConfigInit(&options, cmdline)))
469 config = first->next ? first->next : first;
470 } else if ((config->next = AFPConfigInit(&options, cmdline))) {
471 config = config->next->next ? config->next->next : config->next;
478 return AFPConfigInit(cmdline, cmdline);