2 * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
3 * All Rights Reserved. See COPYRIGHT.
8 #endif /* HAVE_CONFIG_H */
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
23 #endif /* USE_SRVLOC */
25 #include <atalk/logger.h>
26 #include <atalk/util.h>
27 #include <atalk/dsi.h>
28 #include <atalk/afp.h>
29 #include <atalk/compat.h>
30 #include <atalk/server_child.h>
33 #include <atalk/ldapconfig.h>
37 #include "afp_config.h"
41 #include "afp_zeroconf.h"
45 /* get rid of unneeded configurations. i use reference counts to deal
46 * w/ multiple configs sharing the same afp_options. oh, to dream of
47 * garbage collection ... */
48 void configfree(AFPConfig *configs, const AFPConfig *config)
52 for (p = configs; p; p = q) {
57 /* do a little reference counting */
58 if (--(*p->optcount) < 1) {
59 afp_options_free(&p->obj.options, p->defoptions);
63 switch (p->obj.proto) {
72 /* the master loaded the volumes for zeroconf, get rid of that */
73 unload_volumes_and_extmap();
77 static void SRVLOC_callback(SLPHandle hslp _U_, SLPError errcode, void *cookie) {
78 *(SLPError*)cookie = errcode;
81 static char hex[17] = "0123456789abcdef";
83 static char * srvloc_encode(const struct afp_options *options, const char *name)
90 /* Convert name to maccharset */
91 if ((size_t)-1 ==(convert_string_allocate( options->unixcharset, options->maccharset,
92 name, -1, &conv_name)) )
95 /* Escape characters */
97 while (*p && i<(sizeof(buf)-4)) {
100 else if (isspace(*p)) {
106 else if ((!isascii(*p)) || *p <= 0x2f || *p == 0x3f ) {
108 buf[i++] = hex[*p >> 4];
109 buf[i++] = hex[*p++ & 15];
121 #endif /* USE_SRVLOC */
123 static void dsi_cleanup(const AFPConfig *config)
127 SLPError callbackerr;
129 DSI *dsi = (DSI *)config->obj.handle;
131 /* Do nothing if we didn't register. */
132 if (!dsi || dsi->srvloc_url[0] == '\0')
135 err = SLPOpen("en", SLP_FALSE, &hslp);
137 LOG(log_error, logtype_afpd, "dsi_cleanup: Error opening SRVLOC handle");
138 goto srvloc_dereg_err;
146 LOG(log_error, logtype_afpd, "dsi_cleanup: Error unregistering %s from SRVLOC", dsi->srvloc_url);
147 goto srvloc_dereg_err;
150 if (callbackerr != SLP_OK) {
151 LOG(log_error, logtype_afpd, "dsi_cleanup: Error in callback while trying to unregister %s from SRVLOC (%d)", dsi->srvloc_url, callbackerr);
152 goto srvloc_dereg_err;
156 dsi->srvloc_url[0] = '\0';
158 #endif /* USE_SRVLOC */
161 static afp_child_t *dsi_start(AFPConfig *config, AFPConfig *configs,
162 server_child *server_children)
164 DSI *dsi = config->obj.handle;
165 afp_child_t *child = NULL;
167 if (!(child = dsi_getsession(dsi,
169 config->obj.options.tickleval))) {
170 LOG(log_error, logtype_afpd, "dsi_start: session error: %s", strerror(errno));
175 if (parent_or_child == 1) {
176 configfree(configs, config);
177 config->obj.ipc_fd = child->ipc_fds[1];
178 close(child->ipc_fds[0]); /* Close parent IPC fd */
180 afp_over_dsi(&config->obj); /* start a session */
187 static AFPConfig *DSIConfigInit(const struct afp_options *options,
188 unsigned char *refcount,
189 const dsi_proto protocol)
195 if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL) {
196 LOG(log_error, logtype_afpd, "DSIConfigInit: malloc(config): %s", strerror(errno) );
200 LOG(log_debug, logtype_afpd, "DSIConfigInit: hostname: %s, ip/port: %s/%s, ",
202 options->ipaddr ? options->ipaddr : "default",
203 options->port ? options->port : "548");
205 if ((dsi = dsi_init(protocol, "afpd", options->hostname,
206 options->ipaddr, options->port,
207 options->flags & OPTION_PROXY,
208 options->server_quantum)) == NULL) {
209 LOG(log_error, logtype_afpd, "main: dsi_init: %s", strerror(errno) );
213 dsi->dsireadbuf = options->dsireadbuf;
215 if (options->flags & OPTION_PROXY) {
216 LOG(log_note, logtype_afpd, "AFP/TCP proxy initialized for %s:%d (%s)",
217 getip_string((struct sockaddr *)&dsi->server), getip_port((struct sockaddr *)&dsi->server), VERSION);
219 LOG(log_note, logtype_afpd, "AFP/TCP started, advertising %s:%d (%s)",
220 getip_string((struct sockaddr *)&dsi->server), getip_port((struct sockaddr *)&dsi->server), VERSION);
224 dsi->srvloc_url[0] = '\0'; /* Mark that we haven't registered. */
225 if (!(options->flags & OPTION_NOSLP)) {
227 SLPError callbackerr;
229 unsigned int afp_port;
231 char *srvloc_hostname;
232 const char *hostname;
234 err = SLPOpen("en", SLP_FALSE, &hslp);
236 LOG(log_error, logtype_afpd, "DSIConfigInit: Error opening SRVLOC handle");
240 /* XXX We don't want to tack on the port number if we don't have to.
242 * Well, this seems to break MacOS < 10. If the user _really_ wants to
243 * use a non-default port, they can, but be aware, this server might
244 * not show up int the Network Browser.
246 afp_port = getip_port((struct sockaddr *)&dsi->server);
247 /* If specified use the FQDN to register with srvloc, otherwise use IP. */
250 hostname = options->fqdn;
251 p = strchr(hostname, ':');
254 hostname = getip_string((struct sockaddr *)&dsi->server);
256 srvloc_hostname = srvloc_encode(options, (options->server ? options->server : options->hostname));
258 if ((p) || afp_port == 548) {
259 l = snprintf(dsi->srvloc_url, sizeof(dsi->srvloc_url), "afp://%s/?NAME=%s", hostname, srvloc_hostname);
262 l = snprintf(dsi->srvloc_url, sizeof(dsi->srvloc_url), "afp://%s:%d/?NAME=%s", hostname, afp_port, srvloc_hostname);
265 if (l == -1 || l >= (int)sizeof(dsi->srvloc_url)) {
266 LOG(log_error, logtype_afpd, "DSIConfigInit: Hostname is too long for SRVLOC");
267 dsi->srvloc_url[0] = '\0';
273 SLP_LIFETIME_MAXIMUM,
280 LOG(log_error, logtype_afpd, "DSIConfigInit: Error registering %s with SRVLOC", dsi->srvloc_url);
281 dsi->srvloc_url[0] = '\0';
285 if (callbackerr != SLP_OK) {
286 LOG(log_error, logtype_afpd, "DSIConfigInit: Error in callback trying to register %s with SRVLOC", dsi->srvloc_url);
287 dsi->srvloc_url[0] = '\0';
291 LOG(log_info, logtype_afpd, "Sucessfully registered %s with SRVLOC", dsi->srvloc_url);
292 config->server_cleanup = dsi_cleanup;
297 #endif /* USE_SRVLOC */
299 config->fd = dsi->serversock;
300 config->obj.handle = dsi;
301 config->obj.config = config;
302 config->obj.proto = AFPPROTO_DSI;
304 memcpy(&config->obj.options, options, sizeof(struct afp_options));
305 /* get rid of any appletalk info. we use the fact that the DSI
306 * stuff is done after the ASP stuff. */
307 p = config->obj.options.server;
308 if (p && (q = strchr(p, ':')))
311 config->optcount = refcount;
314 config->server_start = dsi_start;
318 /* allocate server configurations. this should really store the last
319 * entry in config->last or something like that. that would make
320 * supporting multiple dsi transports easier. */
321 static AFPConfig *AFPConfigInit(struct afp_options *options,
322 const struct afp_options *defoptions)
324 AFPConfig *next = NULL;
325 unsigned char *refcount;
327 if ((refcount = (unsigned char *)
328 calloc(1, sizeof(unsigned char))) == NULL) {
329 LOG(log_error, logtype_afpd, "AFPConfigInit: calloc(refcount): %s", strerror(errno) );
334 set_signature(options);
336 /* handle dsi transports and dsi proxies. we only proxy
337 * for DSI connections. */
339 /* this should have something like the following:
340 * for (i=mindsi; i < maxdsi; i++)
341 * if (options->transports & (1 << i) &&
342 * (next = DSIConfigInit(options, refcount, i)))
343 * next->defoptions = defoptions;
345 if ( (options->transports & AFPTRANS_TCP)
347 ((options->flags & OPTION_PROXY) == 0)
349 (next = DSIConfigInit(options, refcount, DSI_TCPIP)))
350 next->defoptions = defoptions;
352 /* load in all the authentication modules. we can load the same
353 things multiple times if necessary. however, loading different
354 things with the same names will cause complaints. by not loading
355 in any uams with proxies, we prevent ddp connections from succeeding.
357 auth_load(options->uampath, options->uamlist);
359 /* this should be able to accept multiple dsi transports. i think
360 * the only thing that gets affected is the net addresses. */
361 status_init(next, options);
366 /* fill in the appropriate bits for each interface */
367 AFPConfig *configinit(struct afp_options *cmdline)
370 char buf[LINESIZE + 1], *p, have_option = 0;
372 struct afp_options options;
373 AFPConfig *config=NULL, *first = NULL;
375 /* if config file doesn't exist, load defaults */
376 if ((fp = fopen(cmdline->configfile, "r")) == NULL)
378 LOG(log_debug, logtype_afpd, "ConfigFile %s not found, assuming defaults",
379 cmdline->configfile);
380 return AFPConfigInit(cmdline, cmdline);
383 /* scan in the configuration file */
386 if (!fgets(&buf[len], LINESIZE - len, fp) || buf[len] == '#')
389 if ( len >= 2 && buf[len-2] == '\\' ) {
395 /* a little pre-processing to get rid of spaces and end-of-lines */
397 while (p && isspace(*p))
399 if (!p || (*p == '\0'))
404 memcpy(&options, cmdline, sizeof(options));
405 if (!afp_options_parseline(p, &options))
408 /* AFPConfigInit can return two linked configs due to DSI and ASP */
410 if ((first = AFPConfigInit(&options, cmdline)))
411 config = first->next ? first->next : first;
412 } else if ((config->next = AFPConfigInit(&options, cmdline))) {
413 config = config->next->next ? config->next->next : config->next;
418 /* Parse afp_ldap.conf */
419 acl_ldap_readconfig(_PATH_ACL_LDAPCONF);
420 #endif /* HAVE_LDAP */
422 LOG(log_debug, logtype_afpd, "Finished parsing Config File");
426 first = AFPConfigInit(cmdline, cmdline);
428 /* Now register with zeroconf, we also need the volumes for that */
429 if (! (first->obj.options.flags & OPTION_NOZEROCONF)) {
430 load_volumes(&first->obj);
431 zeroconf_register(first);