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