]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/afp_config.c
BIG commit to improve code style using astyle as well as fix up CNID DB
[netatalk.git] / etc / afpd / afp_config.c
1 /*
2  * $Id: afp_config.c,v 1.8 2001-12-03 05:03:38 jmarcus Exp $
3  *
4  * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
5  * All Rights Reserved.  See COPYRIGHT.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif /* HAVE_CONFIG_H */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14
15 /* STDC check */
16 #if STDC_HEADERS
17 #include <string.h>
18 #else /* STDC_HEADERS */
19 #ifndef HAVE_STRCHR
20 #define strchr index
21 #define strrchr index
22 #endif /* HAVE_STRCHR */
23 char *strchr (), *strrchr ();
24 #ifndef HAVE_MEMCPY
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 */
29
30 #ifdef HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif /* HAVE_UNISTD_H */
33 #include <ctype.h>
34 #include <syslog.h>
35
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
39
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>
47 #ifdef USE_SRVLOC
48 #include <slp.h>
49 static char srvloc_url[512];
50 #endif /* USE_SRVLOC */
51
52 #include "globals.h"
53 #include "afp_config.h"
54 #include "uam_auth.h"
55 #include "status.h"
56
57 #define LINESIZE 1024  
58
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)
63 {
64     AFPConfig *p, *q;
65
66     for (p = configs; p; p = q) {
67         q = p->next;
68         if (p == config)
69             continue;
70
71         /* do a little reference counting */
72         if (--(*p->optcount) < 1) {
73             afp_options_free(&p->obj.options, p->defoptions);
74             free(p->optcount);
75         }
76
77         switch (p->obj.proto) {
78 #ifndef NO_DDP
79         case AFPPROTO_ASP:
80             free(p->obj.Obj);
81             free(p->obj.Type);
82             free(p->obj.Zone);
83             atp_close(((ASP) p->obj.handle)->asp_atp);
84             free(p->obj.handle);
85             break;
86 #endif /* no afp/asp */
87         case AFPPROTO_DSI:
88             close(p->fd);
89             free(p->obj.handle);
90             break;
91         }
92         free(p);
93     }
94 }
95
96 #ifdef USE_SRVLOC
97 static void SRVLOC_callback(SLPHandle hslp, SLPError errcode, void *cookie) {
98     *(SLPError*)cookie = errcode;
99 }
100 #endif /* USE_SRVLOC */
101
102 #ifdef USE_SRVLOC
103 static void dsi_cleanup(const AFPConfig *config)
104 {
105     SLPError err;
106     SLPError callbackerr;
107     SLPHandle hslp;
108     err = SLPOpen("en", SLP_FALSE, &hslp);
109     if (err != SLP_OK) {
110         syslog(LOG_ERR, "Error opening SRVLOC handle");
111         goto srvloc_dereg_err;
112     }
113
114     err = SLPDereg(hslp,
115                    srvloc_url,
116                    SRVLOC_callback,
117                    &callbackerr);
118     if (err != SLP_OK) {
119         syslog(LOG_ERR, "Error unregistering %s from SRVLOC", srvloc_url);
120         goto srvloc_dereg_err;
121     }
122
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;
126     }
127
128 srvloc_dereg_err:
129     SLPClose(hslp);
130 }
131 #endif /* USE_SRVLOC */
132
133 #ifndef NO_DDP
134 static void asp_cleanup(const AFPConfig *config)
135 {
136     nbp_unrgstr(config->obj.Obj, config->obj.Type, config->obj.Zone,
137                 &config->obj.options.ddpaddr);
138 }
139
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)
144 {
145     ASP asp;
146
147     if (!(asp = asp_getsession(config->obj.handle, server_children,
148                                config->obj.options.tickleval))) {
149         syslog( LOG_ERR, "main: asp_getsession: %m" );
150         exit( 1 );
151     }
152
153     if (asp->child) {
154         configfree(configs, config); /* free a bunch of stuff */
155         afp_over_asp(&config->obj);
156         exit (0);
157     }
158
159     return 0;
160 }
161 #endif /* no afp/asp */
162
163 static int dsi_start(AFPConfig *config, AFPConfig *configs,
164                      server_child *server_children)
165 {
166     DSI *dsi;
167
168     if (!(dsi = dsi_getsession(config->obj.handle, server_children,
169                                config->obj.options.tickleval))) {
170         syslog( LOG_ERR, "main: dsi_getsession: %m" );
171         exit( 1 );
172     }
173
174     /* we've forked. */
175     if (dsi->child) {
176         configfree(configs, config);
177         afp_over_dsi(&config->obj); /* start a session */
178         exit (0);
179     }
180
181     return 0;
182 }
183
184 #ifndef NO_DDP
185 static AFPConfig *ASPConfigInit(const struct afp_options *options,
186                                 unsigned char *refcount)
187 {
188     AFPConfig *config;
189     ATP atp;
190     ASP asp;
191     char *Obj, *Type = "AFPServer", *Zone = "*";
192
193     if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL)
194         return NULL;
195
196     if ((atp = atp_open(ATADDR_ANYPORT, &options->ddpaddr)) == NULL)  {
197         syslog( LOG_ERR, "main: atp_open: %m");
198         free(config);
199         return NULL;
200     }
201
202     if ((asp = asp_init( atp )) == NULL) {
203         syslog( LOG_ERR, "main: asp_init: %m" );
204         atp_close(atp);
205         free(config);
206         return NULL;
207     }
208
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;
214     }
215
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;
220
221     if ((config->obj.Type = strdup(Type)) == NULL) {
222         free(config->obj.Obj);
223         goto serv_free_return;
224     }
225
226     if ((config->obj.Zone = strdup(Zone)) == NULL) {
227         free(config->obj.Obj);
228         free(config->obj.Type);
229         goto serv_free_return;
230     }
231
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;
240     }
241
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 );
246
247     config->fd = atp_fileno(atp);
248     config->obj.handle = asp;
249     config->obj.config = config;
250     config->obj.proto = AFPPROTO_ASP;
251
252     memcpy(&config->obj.options, options, sizeof(struct afp_options));
253     config->optcount = refcount;
254     (*refcount)++;
255
256     config->server_start = asp_start;
257     config->server_cleanup = asp_cleanup;
258
259     return config;
260
261 serv_free_return:
262                     asp_close(asp);
263     free(config);
264     return NULL;
265 }
266 #endif /* no afp/asp */
267
268
269 static AFPConfig *DSIConfigInit(const struct afp_options *options,
270                                 unsigned char *refcount,
271                                 const dsi_proto protocol)
272 {
273     AFPConfig *config;
274     DSI *dsi;
275     char *p, *q;
276 #ifdef USE_SRVLOC
277     SLPError err;
278     SLPError callbackerr;
279     SLPHandle hslp;
280     struct servent *afpovertcp;
281 #endif /* USE_SRVLOC */
282
283     if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL) {
284         syslog( LOG_ERR, "DSIConfigInit: malloc(config): %m" );
285         return NULL;
286     }
287
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" );
293         free(config);
294         return NULL;
295     }
296
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),
300                VERSION);
301     } else {
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);
305     }
306
307 #ifdef USE_SRVLOC
308     err = SLPOpen("en", SLP_FALSE, &hslp);
309     if (err != SLP_OK) {
310         syslog(LOG_ERR, "Error opening SRVLOC handle");
311         goto srvloc_reg_err;
312     }
313
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);
321     }
322     else {
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);
324     }
325
326     err = SLPReg(hslp,
327                  srvloc_url,
328                  SLP_LIFETIME_MAXIMUM,
329                  "",
330                  "",
331                  SLP_TRUE,
332                  SRVLOC_callback,
333                  &callbackerr);
334     if (err != SLP_OK) {
335         syslog(LOG_ERR, "Error registering %s with SRVLOC", srvloc_url);
336         goto srvloc_reg_err;
337     }
338
339     if (callbackerr != SLP_OK) {
340         syslog(LOG_ERR, "Error in callback trying to register %s with SRVLOC", srvloc_url);
341         goto srvloc_reg_err;
342     }
343
344     syslog(LOG_INFO, "Sucessfully registered %s with SRVLOC", srvloc_url);
345
346 srvloc_reg_err:
347     SLPClose(hslp);
348 #endif /* USE_SRVLOC */
349
350
351     config->fd = dsi->serversock;
352     config->obj.handle = dsi;
353     config->obj.config = config;
354     config->obj.proto = AFPPROTO_DSI;
355
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, ':')))
361         *q = '\0';
362
363     config->optcount = refcount;
364     (*refcount)++;
365
366     config->server_start = dsi_start;
367 #ifdef USE_SRVLOC
368     config->server_cleanup = dsi_cleanup;
369 #endif /* USE_SRVLOC */
370     return config;
371 }
372
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)
378 {
379     AFPConfig *config = NULL, *next = NULL;
380     unsigned char *refcount;
381
382     if ((refcount = (unsigned char *)
383                     calloc(1, sizeof(unsigned char))) == NULL) {
384         syslog( LOG_ERR, "AFPConfigInit: calloc(refcount): %m" );
385         return NULL;
386     }
387
388 #ifndef NO_DDP
389     /* handle asp transports */
390     if ((options->transports & AFPTRANS_DDP) &&
391             (config = ASPConfigInit(options, refcount)))
392         config->defoptions = defoptions;
393 #endif /* NO_DDP */
394
395     /* handle dsi transports and dsi proxies. we only proxy
396      * for DSI connections. */
397
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;
403      */
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;
409
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.
414     */
415     auth_load(options->uampath, options->uamlist);
416
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);
420
421     /* attach dsi config to tail of asp config */
422     if (config) {
423         config->next = next;
424         return config;
425     }
426
427     return next;
428 }
429
430 /* fill in the appropriate bits for each interface */
431 AFPConfig *configinit(struct afp_options *cmdline)
432 {
433     FILE *fp;
434     char buf[LINESIZE + 1], *p, have_option = 0;
435     struct afp_options options;
436     AFPConfig *config, *first = NULL;
437
438     /* if config file doesn't exist, load defaults */
439     if ((fp = fopen(cmdline->configfile, "r")) == NULL)
440         return AFPConfigInit(cmdline, cmdline);
441
442     /* scan in the configuration file */
443     while (!feof(fp)) {
444         if (!fgets(buf, sizeof(buf), fp) || buf[0] == '#')
445             continue;
446
447         /* a little pre-processing to get rid of spaces and end-of-lines */
448         p = buf;
449         while (p && isspace(*p))
450             p++;
451         if (!p || (*p == '\0'))
452             continue;
453
454         have_option = 1;
455
456         memcpy(&options, cmdline, sizeof(options));
457         if (!afp_options_parseline(p, &options))
458             continue;
459
460         /* this should really get a head and a tail to simplify things. */
461         if (!first) {
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;
466         }
467     }
468
469     fclose(fp);
470
471     if (!have_option)
472         return AFPConfigInit(cmdline, cmdline);
473
474     return first;
475 }