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