]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/afp_config.c
commenting changes, more autoconf support in afpd, etc
[netatalk.git] / etc / afpd / afp_config.c
1 /* 
2  * $Id: afp_config.c,v 1.3 2001-06-20 18:33:04 rufustfirefly 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 #include <string.h>
15 #ifdef HAVE_UNISTD_H
16 #include <unistd.h>
17 #endif /* HAVE_UNISTD_H */
18 #include <ctype.h>
19 #include <syslog.h>
20
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
24
25 #include <atalk/dsi.h>
26 #include <atalk/atp.h>
27 #include <atalk/asp.h>
28 #include <atalk/nbp.h>
29 #include <atalk/afp.h>
30 #include <atalk/compat.h>
31 #include <atalk/server_child.h>
32
33 #include "globals.h"
34 #include "afp_config.h"
35 #include "uam_auth.h"
36 #include "status.h"
37
38 #define LINESIZE 1024  
39
40 /* get rid of unneeded configurations. i use reference counts to deal
41  * w/ multiple configs sharing the same afp_options. oh, to dream of
42  * garbage collection ... */
43 void configfree(AFPConfig *configs, const AFPConfig *config)
44 {
45   AFPConfig *p, *q;
46
47   for (p = configs; p; p = q) {
48     q = p->next;
49     if (p == config)
50       continue;
51
52     /* do a little reference counting */
53     if (--(*p->optcount) < 1) {
54       afp_options_free(&p->obj.options, p->defoptions);
55       free(p->optcount);
56     }
57
58     switch (p->obj.proto) {
59 #ifndef NO_DDP
60     case AFPPROTO_ASP:
61       free(p->obj.Obj);
62       free(p->obj.Type);
63       free(p->obj.Zone);
64       atp_close(((ASP) p->obj.handle)->asp_atp);
65       free(p->obj.handle);
66       break;
67 #endif /* no afp/asp */
68     case AFPPROTO_DSI:
69       close(p->fd);
70       free(p->obj.handle);
71       break;
72     }
73     free(p);
74   }
75 }
76
77 #ifndef NO_DDP
78 static void asp_cleanup(const AFPConfig *config)
79 {
80   nbp_unrgstr(config->obj.Obj, config->obj.Type, config->obj.Zone,
81               &config->obj.options.ddpaddr);
82 }
83
84 /* these two are almost identical. it should be possible to collapse them
85  * into one with minimal junk. */
86 static int asp_start(AFPConfig *config, AFPConfig *configs, 
87                      server_child *server_children) 
88 {
89   ASP asp;
90
91   if (!(asp = asp_getsession(config->obj.handle, server_children, 
92                              config->obj.options.tickleval))) {
93     syslog( LOG_ERR, "main: asp_getsession: %m" );
94     exit( 1 );
95   } 
96   
97   if (asp->child) {
98     configfree(configs, config); /* free a bunch of stuff */
99     afp_over_asp(&config->obj);
100     exit (0);
101   }
102
103   return 0;
104 }
105 #endif /* no afp/asp */
106
107 static int dsi_start(AFPConfig *config, AFPConfig *configs,
108                      server_child *server_children)
109 {
110   DSI *dsi;
111
112   if (!(dsi = dsi_getsession(config->obj.handle, server_children,
113                              config->obj.options.tickleval))) {
114     syslog( LOG_ERR, "main: dsi_getsession: %m" );
115     exit( 1 );
116   } 
117   
118   /* we've forked. */
119   if (dsi->child) {
120     configfree(configs, config);
121     afp_over_dsi(&config->obj); /* start a session */
122     exit (0);
123   }
124
125   return 0;
126 }
127
128 #ifndef NO_DDP
129 static AFPConfig *ASPConfigInit(const struct afp_options *options,
130                                 unsigned char *refcount)
131 {
132   AFPConfig *config;
133   ATP atp;
134   ASP asp;
135   char *Obj, *Type = "AFPServer", *Zone = "*";
136   
137   if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL)
138     return NULL;
139   
140   if ((atp = atp_open(ATADDR_ANYPORT, &options->ddpaddr)) == NULL)  {
141     syslog( LOG_ERR, "main: atp_open: %m");
142     free(config);
143     return NULL;
144   }
145   
146   if ((asp = asp_init( atp )) == NULL) {
147     syslog( LOG_ERR, "main: asp_init: %m" );
148     atp_close(atp);
149     free(config);
150     return NULL;
151   }
152   
153   /* register asp server */
154   Obj = (char *) options->hostname;
155   if (nbp_name(options->server, &Obj, &Type, &Zone )) {
156     syslog( LOG_ERR, "main: can't parse %s", options->server );
157     goto serv_free_return;
158   }
159
160   /* dup Obj, Type and Zone as they get assigned to a single internal
161    * buffer by nbp_name */
162   if ((config->obj.Obj  = strdup(Obj)) == NULL) 
163     goto serv_free_return;
164
165   if ((config->obj.Type = strdup(Type)) == NULL) {
166     free(config->obj.Obj);
167     goto serv_free_return;
168   }
169
170   if ((config->obj.Zone = strdup(Zone)) == NULL) {
171     free(config->obj.Obj);
172     free(config->obj.Type);
173     goto serv_free_return;
174   }
175   
176   /* make sure we're not registered */
177   nbp_unrgstr(Obj, Type, Zone, &options->ddpaddr); 
178   if (nbp_rgstr( atp_sockaddr( atp ), Obj, Type, Zone ) < 0 ) {
179     syslog( LOG_ERR, "Can't register %s:%s@%s", Obj, Type, Zone );
180     free(config->obj.Obj);
181     free(config->obj.Type);
182     free(config->obj.Zone);
183     goto serv_free_return;
184   }
185
186   syslog( LOG_INFO, "%s:%s@%s started on %u.%u:%u (%s)", Obj, Type, Zone,
187           ntohs( atp_sockaddr( atp )->sat_addr.s_net ),
188           atp_sockaddr( atp )->sat_addr.s_node,
189           atp_sockaddr( atp )->sat_port, VERSION );
190   
191   config->fd = atp_fileno(atp);
192   config->obj.handle = asp;
193   config->obj.config = config;
194   config->obj.proto = AFPPROTO_ASP;
195
196   memcpy(&config->obj.options, options, sizeof(struct afp_options));
197   config->optcount = refcount;
198   (*refcount)++;
199
200   config->server_start = asp_start;
201   config->server_cleanup = asp_cleanup;
202
203   return config;
204
205 serv_free_return:
206   asp_close(asp);
207   free(config);
208   return NULL;
209 }
210 #endif /* no afp/asp */
211
212
213 static AFPConfig *DSIConfigInit(const struct afp_options *options,
214                                 unsigned char *refcount,
215                                 const dsi_proto protocol) 
216 {
217   AFPConfig *config;
218   DSI *dsi;
219   char *p, *q;
220
221   if ((config = (AFPConfig *) calloc(1, sizeof(AFPConfig))) == NULL) {
222     syslog( LOG_ERR, "DSIConfigInit: malloc(config): %m" );
223     return NULL;
224   }
225
226   if ((dsi = dsi_init(protocol, "afpd", options->hostname,
227                       options->ipaddr, options->port, 
228                       options->flags & OPTION_PROXY, 
229                       options->server_quantum)) == NULL) {
230     syslog( LOG_ERR, "main: dsi_init: %m" );
231     free(config);
232     return NULL;
233   }
234
235   if (options->flags & OPTION_PROXY) {
236     syslog(LOG_INFO, "ASIP proxy initialized for %s:%d (%s)",
237            inet_ntoa(dsi->server.sin_addr), ntohs(dsi->server.sin_port), 
238            VERSION);
239   } else {
240     syslog(LOG_INFO, "ASIP started on %s:%d(%d) (%s)",
241            inet_ntoa(dsi->server.sin_addr), ntohs(dsi->server.sin_port), 
242            dsi->serversock, VERSION);
243   }
244
245   config->fd = dsi->serversock;
246   config->obj.handle = dsi;
247   config->obj.config = config;
248   config->obj.proto = AFPPROTO_DSI;
249
250   memcpy(&config->obj.options, options, sizeof(struct afp_options));
251   /* get rid of any appletalk info. we use the fact that the DSI
252    * stuff is done after the ASP stuff. */
253   p = config->obj.options.server;
254   if (p && (q = strchr(p, ':')))
255     *q = '\0';
256     
257   config->optcount = refcount;
258   (*refcount)++;
259
260   config->server_start = dsi_start;
261   return config;
262 }
263
264 /* allocate server configurations. this should really store the last
265  * entry in config->last or something like that. that would make
266  * supporting multiple dsi transports easier. */
267 static AFPConfig *AFPConfigInit(const struct afp_options *options,
268                                 const struct afp_options *defoptions)
269 {
270   AFPConfig *config = NULL, *next = NULL;
271   unsigned char *refcount;
272
273   if ((refcount = (unsigned char *) 
274        calloc(1, sizeof(unsigned char))) == NULL) {
275     syslog( LOG_ERR, "AFPConfigInit: calloc(refcount): %m" );
276     return NULL;
277   }
278
279 #ifndef NO_DDP
280   /* handle asp transports */
281   if ((options->transports & AFPTRANS_DDP) && 
282       (config = ASPConfigInit(options, refcount)))
283     config->defoptions = defoptions;
284 #endif /* NO_DDP */
285
286   /* handle dsi transports and dsi proxies. we only proxy
287    * for DSI connections. */
288
289   /* this should have something like the following:
290    * for (i=mindsi; i < maxdsi; i++)
291    *   if (options->transports & (1 << i) && 
292    *     (next = DSIConfigInit(options, refcount, i)))
293    *     next->defoptions = defoptions;
294    */
295   if ((options->transports & AFPTRANS_TCP) &&
296       (((options->flags & OPTION_PROXY) == 0) ||
297        ((options->flags & OPTION_PROXY) && config))
298       && (next = DSIConfigInit(options, refcount, DSI_TCPIP)))
299     next->defoptions = defoptions;
300
301   /* load in all the authentication modules. we can load the same
302      things multiple times if necessary. however, loading different
303      things with the same names will cause complaints. by not loading
304      in any uams with proxies, we prevent ddp connections from succeeding.
305   */
306   auth_load(options->uampath, options->uamlist);
307
308   /* this should be able to accept multiple dsi transports. i think
309    * the only thing that gets affected is the net addresses. */
310   status_init(config, next, options);
311
312   /* attach dsi config to tail of asp config */
313   if (config) {
314     config->next = next;
315     return config;
316   } 
317     
318   return next;
319 }
320
321 /* fill in the appropriate bits for each interface */
322 AFPConfig *configinit(struct afp_options *cmdline)
323 {
324   FILE *fp;
325   char buf[LINESIZE + 1], *p, have_option = 0;
326   struct afp_options options;
327   AFPConfig *config, *first = NULL;
328
329   /* if config file doesn't exist, load defaults */
330   if ((fp = fopen(cmdline->configfile, "r")) == NULL) 
331     return AFPConfigInit(cmdline, cmdline);
332
333   /* scan in the configuration file */
334   while (!feof(fp)) {
335     if (!fgets(buf, sizeof(buf), fp) || buf[0] == '#')
336       continue;
337     
338     /* a little pre-processing to get rid of spaces and end-of-lines */
339     p = buf;
340     while (p && isspace(*p)) 
341       p++;
342     if (!p || (*p == '\0'))
343       continue;
344
345     have_option = 1;
346
347     memcpy(&options, cmdline, sizeof(options));
348     if (!afp_options_parseline(p, &options))
349       continue;
350
351     /* this should really get a head and a tail to simplify things. */
352     if (!first) {
353       if ((first = AFPConfigInit(&options, cmdline)))
354         config = first->next ? first->next : first;
355     } else if ((config->next = AFPConfigInit(&options, cmdline))) {
356       config = config->next->next ? config->next->next : config->next;
357     }
358   }
359
360   fclose(fp);
361
362   if (!have_option)
363     return AFPConfigInit(cmdline, cmdline);
364
365   return first;
366 }