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) );
214 if (options->flags & OPTION_PROXY) {
215 LOG(log_note, logtype_afpd, "AFP/TCP proxy initialized for %s:%d (%s)",
216 getip_string((struct sockaddr *)&dsi->server), getip_port((struct sockaddr *)&dsi->server), VERSION);
218 LOG(log_note, logtype_afpd, "AFP/TCP started, advertising %s:%d (%s)",
219 getip_string((struct sockaddr *)&dsi->server), getip_port((struct sockaddr *)&dsi->server), VERSION);
223 dsi->srvloc_url[0] = '\0'; /* Mark that we haven't registered. */
224 if (!(options->flags & OPTION_NOSLP)) {
226 SLPError callbackerr;
228 unsigned int afp_port;
230 char *srvloc_hostname;
231 const char *hostname;
233 err = SLPOpen("en", SLP_FALSE, &hslp);
235 LOG(log_error, logtype_afpd, "DSIConfigInit: Error opening SRVLOC handle");
239 /* XXX We don't want to tack on the port number if we don't have to.
241 * Well, this seems to break MacOS < 10. If the user _really_ wants to
242 * use a non-default port, they can, but be aware, this server might
243 * not show up int the Network Browser.
245 afp_port = getip_port((struct sockaddr *)&dsi->server);
246 /* If specified use the FQDN to register with srvloc, otherwise use IP. */
249 hostname = options->fqdn;
250 p = strchr(hostname, ':');
253 hostname = getip_string((struct sockaddr *)&dsi->server);
255 srvloc_hostname = srvloc_encode(options, (options->server ? options->server : options->hostname));
257 if ((p) || afp_port == 548) {
258 l = snprintf(dsi->srvloc_url, sizeof(dsi->srvloc_url), "afp://%s/?NAME=%s", hostname, srvloc_hostname);
261 l = snprintf(dsi->srvloc_url, sizeof(dsi->srvloc_url), "afp://%s:%d/?NAME=%s", hostname, afp_port, srvloc_hostname);
264 if (l == -1 || l >= (int)sizeof(dsi->srvloc_url)) {
265 LOG(log_error, logtype_afpd, "DSIConfigInit: Hostname is too long for SRVLOC");
266 dsi->srvloc_url[0] = '\0';
272 SLP_LIFETIME_MAXIMUM,
279 LOG(log_error, logtype_afpd, "DSIConfigInit: Error registering %s with SRVLOC", dsi->srvloc_url);
280 dsi->srvloc_url[0] = '\0';
284 if (callbackerr != SLP_OK) {
285 LOG(log_error, logtype_afpd, "DSIConfigInit: Error in callback trying to register %s with SRVLOC", dsi->srvloc_url);
286 dsi->srvloc_url[0] = '\0';
290 LOG(log_info, logtype_afpd, "Sucessfully registered %s with SRVLOC", dsi->srvloc_url);
291 config->server_cleanup = dsi_cleanup;
296 #endif /* USE_SRVLOC */
298 config->fd = dsi->serversock;
299 config->obj.handle = dsi;
300 config->obj.config = config;
301 config->obj.proto = AFPPROTO_DSI;
303 memcpy(&config->obj.options, options, sizeof(struct afp_options));
304 /* get rid of any appletalk info. we use the fact that the DSI
305 * stuff is done after the ASP stuff. */
306 p = config->obj.options.server;
307 if (p && (q = strchr(p, ':')))
310 config->optcount = refcount;
313 config->server_start = dsi_start;
317 /* allocate server configurations. this should really store the last
318 * entry in config->last or something like that. that would make
319 * supporting multiple dsi transports easier. */
320 static AFPConfig *AFPConfigInit(struct afp_options *options,
321 const struct afp_options *defoptions)
323 AFPConfig *next = NULL;
324 unsigned char *refcount;
326 if ((refcount = (unsigned char *)
327 calloc(1, sizeof(unsigned char))) == NULL) {
328 LOG(log_error, logtype_afpd, "AFPConfigInit: calloc(refcount): %s", strerror(errno) );
333 set_signature(options);
335 /* handle dsi transports and dsi proxies. we only proxy
336 * for DSI connections. */
338 /* this should have something like the following:
339 * for (i=mindsi; i < maxdsi; i++)
340 * if (options->transports & (1 << i) &&
341 * (next = DSIConfigInit(options, refcount, i)))
342 * next->defoptions = defoptions;
344 if ( (options->transports & AFPTRANS_TCP)
346 ((options->flags & OPTION_PROXY) == 0)
348 (next = DSIConfigInit(options, refcount, DSI_TCPIP)))
349 next->defoptions = defoptions;
351 /* load in all the authentication modules. we can load the same
352 things multiple times if necessary. however, loading different
353 things with the same names will cause complaints. by not loading
354 in any uams with proxies, we prevent ddp connections from succeeding.
356 auth_load(options->uampath, options->uamlist);
358 /* this should be able to accept multiple dsi transports. i think
359 * the only thing that gets affected is the net addresses. */
360 status_init(next, options);
365 /* fill in the appropriate bits for each interface */
366 AFPConfig *configinit(struct afp_options *cmdline)
369 char buf[LINESIZE + 1], *p, have_option = 0;
371 struct afp_options options;
372 AFPConfig *config=NULL, *first = NULL;
374 /* if config file doesn't exist, load defaults */
375 if ((fp = fopen(cmdline->configfile, "r")) == NULL)
377 LOG(log_debug, logtype_afpd, "ConfigFile %s not found, assuming defaults",
378 cmdline->configfile);
379 return AFPConfigInit(cmdline, cmdline);
382 /* scan in the configuration file */
385 if (!fgets(&buf[len], LINESIZE - len, fp) || buf[len] == '#')
388 if ( len >= 2 && buf[len-2] == '\\' ) {
394 /* a little pre-processing to get rid of spaces and end-of-lines */
396 while (p && isspace(*p))
398 if (!p || (*p == '\0'))
403 memcpy(&options, cmdline, sizeof(options));
404 if (!afp_options_parseline(p, &options))
407 /* AFPConfigInit can return two linked configs due to DSI and ASP */
409 if ((first = AFPConfigInit(&options, cmdline)))
410 config = first->next ? first->next : first;
411 } else if ((config->next = AFPConfigInit(&options, cmdline))) {
412 config = config->next->next ? config->next->next : config->next;
417 /* Parse afp_ldap.conf */
418 acl_ldap_readconfig(_PATH_ACL_LDAPCONF);
419 #endif /* HAVE_LDAP */
421 LOG(log_debug, logtype_afpd, "Finished parsing Config File");
425 first = AFPConfigInit(cmdline, cmdline);
427 /* Now register with zeroconf, we also need the volumes for that */
428 load_volumes(&first->obj);
429 zeroconf_register(first);