2 * $Id: afp_config.c,v 1.18 2002-03-31 01:17:34 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 */
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 char *srvloc_hostname;
285 #endif /* USE_SRVLOC */
287 if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL) {
288 LOG(log_error, logtype_afpd, "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 LOG(log_error, logtype_afpd, "main: dsi_init: %s", strerror(errno) );
301 if (options->flags & OPTION_PROXY) {
302 LOG(log_info, logtype_afpd, "ASIP proxy initialized for %s:%d (%s)",
303 inet_ntoa(dsi->server.sin_addr), ntohs(dsi->server.sin_port),
306 LOG(log_info, logtype_afpd, "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 LOG(log_error, logtype_afpd, "DSIConfigInit: 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 srvloc_hostname = (options->server ? options->server : options->hostname);
324 if (afpovertcp != NULL) {
325 afp_port = afpovertcp->s_port;
327 if (strlen(srvloc_hostname) > (sizeof(srvloc_url) - strlen(inet_ntoa(dsi->server.sin_addr)) - 21)) {
328 LOG(log_error, logtype_afpd, "DSIConfigInit: Hostname is too long for SRVLOC");
331 if (dsi->server.sin_port == afp_port) {
332 sprintf(srvloc_url, "afp://%s/?NAME=%s", inet_ntoa(dsi->server.sin_addr), srvloc_hostname);
335 sprintf(srvloc_url, "afp://%s:%d/?NAME=%s", inet_ntoa(dsi->server.sin_addr), ntohs(dsi->server.sin_port), srvloc_hostname);
340 SLP_LIFETIME_MAXIMUM,
347 LOG(log_error, logtype_afpd, "DSIConfigInit: Error registering %s with SRVLOC", srvloc_url);
351 if (callbackerr != SLP_OK) {
352 LOG(log_error, logtype_afpd, "DSIConfigInit: Error in callback trying to register %s with SRVLOC", srvloc_url);
356 LOG(log_info, logtype_afpd, "Sucessfully registered %s with SRVLOC", srvloc_url);
360 #endif /* USE_SRVLOC */
363 config->fd = dsi->serversock;
364 config->obj.handle = dsi;
365 config->obj.config = config;
366 config->obj.proto = AFPPROTO_DSI;
368 memcpy(&config->obj.options, options, sizeof(struct afp_options));
369 /* get rid of any appletalk info. we use the fact that the DSI
370 * stuff is done after the ASP stuff. */
371 p = config->obj.options.server;
372 if (p && (q = strchr(p, ':')))
375 config->optcount = refcount;
378 config->server_start = dsi_start;
380 config->server_cleanup = dsi_cleanup;
381 #endif /* USE_SRVLOC */
385 /* allocate server configurations. this should really store the last
386 * entry in config->last or something like that. that would make
387 * supporting multiple dsi transports easier. */
388 static AFPConfig *AFPConfigInit(const struct afp_options *options,
389 const struct afp_options *defoptions)
391 AFPConfig *config = NULL, *next = NULL;
392 unsigned char *refcount;
394 if ((refcount = (unsigned char *)
395 calloc(1, sizeof(unsigned char))) == NULL) {
396 LOG(log_error, logtype_afpd, "AFPConfigInit: calloc(refcount): %s", strerror(errno) );
401 /* handle asp transports */
402 if ((options->transports & AFPTRANS_DDP) &&
403 (config = ASPConfigInit(options, refcount)))
404 config->defoptions = defoptions;
407 /* handle dsi transports and dsi proxies. we only proxy
408 * for DSI connections. */
410 /* this should have something like the following:
411 * for (i=mindsi; i < maxdsi; i++)
412 * if (options->transports & (1 << i) &&
413 * (next = DSIConfigInit(options, refcount, i)))
414 * next->defoptions = defoptions;
416 if ((options->transports & AFPTRANS_TCP) &&
417 (((options->flags & OPTION_PROXY) == 0) ||
418 ((options->flags & OPTION_PROXY) && config))
419 && (next = DSIConfigInit(options, refcount, DSI_TCPIP)))
420 next->defoptions = defoptions;
422 /* load in all the authentication modules. we can load the same
423 things multiple times if necessary. however, loading different
424 things with the same names will cause complaints. by not loading
425 in any uams with proxies, we prevent ddp connections from succeeding.
427 auth_load(options->uampath, options->uamlist);
429 /* this should be able to accept multiple dsi transports. i think
430 * the only thing that gets affected is the net addresses. */
431 status_init(config, next, options);
433 /* attach dsi config to tail of asp config */
442 /* fill in the appropriate bits for each interface */
443 AFPConfig *configinit(struct afp_options *cmdline)
446 char buf[LINESIZE + 1], *p, have_option = 0;
447 struct afp_options options;
448 AFPConfig *config, *first = NULL;
450 /* if config file doesn't exist, load defaults */
451 if ((fp = fopen(cmdline->configfile, "r")) == NULL)
452 return AFPConfigInit(cmdline, cmdline);
454 /* scan in the configuration file */
456 if (!fgets(buf, sizeof(buf), fp) || buf[0] == '#')
459 /* a little pre-processing to get rid of spaces and end-of-lines */
461 while (p && isspace(*p))
463 if (!p || (*p == '\0'))
468 memcpy(&options, cmdline, sizeof(options));
469 if (!afp_options_parseline(p, &options))
472 /* this should really get a head and a tail to simplify things. */
474 if ((first = AFPConfigInit(&options, cmdline)))
475 config = first->next ? first->next : first;
476 } else if ((config->next = AFPConfigInit(&options, cmdline))) {
477 config = config->next->next ? config->next->next : config->next;
484 return AFPConfigInit(cmdline, cmdline);