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