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