]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/main.c
Add locking RPC to afpd
[netatalk.git] / etc / afpd / main.c
1 /*
2  * Copyright (c) 1990,1993 Regents of The University of Michigan.
3  * All Rights Reserved.  See COPYRIGHT.
4  */
5
6 #ifdef HAVE_CONFIG_H
7 #include "config.h"
8 #endif /* HAVE_CONFIG_H */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <signal.h>
14 #include <sys/param.h>
15 #include <sys/uio.h>
16 #include <sys/time.h>
17 #include <sys/socket.h>
18 #include <errno.h>
19
20 #include <atalk/logger.h>
21 #include <atalk/adouble.h>
22 #include <netatalk/at.h>
23 #include <atalk/compat.h>
24 #include <atalk/dsi.h>
25 #include <atalk/atp.h>
26 #include <atalk/asp.h>
27 #include <atalk/afp.h>
28 #include <atalk/paths.h>
29 #include <atalk/util.h>
30 #include <atalk/server_child.h>
31 #include <atalk/server_ipc.h>
32 #include <atalk/errchk.h>
33 #include <atalk/locking.h>
34
35 #include "event2/event.h"
36 #include "event2/http.h"
37 #include "event2/rpc.h"
38
39 #include "globals.h"
40 #include "afp_config.h"
41 #include "status.h"
42 #include "fork.h"
43 #include "uam_auth.h"
44 #include "afp_zeroconf.h"
45
46 #ifdef TRU64
47 #include <sys/security.h>
48 #include <prot.h>
49 #include <sia.h>
50
51 static int argc = 0;
52 static char **argv = NULL;
53 #endif /* TRU64 */
54
55 unsigned char   nologin = 0;
56
57 struct afp_options default_options;
58
59 static AFPConfig *configs;
60 static server_child *server_children;
61 static fd_set save_rfds;
62 static int    Ipc_fd = -1;
63 static sig_atomic_t reloadconfig = 0;
64
65 #ifdef TRU64
66 void afp_get_cmdline( int *ac, char ***av)
67 {
68     *ac = argc;
69     *av = argv;
70 }
71 #endif /* TRU64 */
72
73 static void afp_exit(const int i)
74 {
75     server_unlock(default_options.pidfile);
76     exit(i);
77 }
78
79 /* ------------------
80    initialize fd set we are waiting for.
81 */
82 static void set_fd(int ipc_fd)
83 {
84     AFPConfig   *config;
85
86     FD_ZERO(&save_rfds);
87     for (config = configs; config; config = config->next) {
88         if (config->fd < 0) /* for proxies */
89             continue;
90         FD_SET(config->fd, &save_rfds);
91     }
92     if (ipc_fd >= 0) {
93         FD_SET(ipc_fd, &save_rfds);
94     }
95 }
96  
97 /* ------------------ */
98 static void afp_goaway(int sig)
99 {
100
101 #ifndef NO_DDP
102     asp_kill(sig);
103 #endif /* ! NO_DDP */
104
105     dsi_kill(sig);
106     switch( sig ) {
107
108     case SIGTERM :
109         LOG(log_note, logtype_afpd, "AFP Server shutting down on SIGTERM");
110         AFPConfig *config;
111         for (config = configs; config; config = config->next)
112             if (config->server_cleanup)
113                 config->server_cleanup(config);
114         afp_exit(0);
115         break;
116
117     case SIGUSR1 :
118         nologin++;
119         auth_unload();
120         LOG(log_info, logtype_afpd, "disallowing logins");        
121         break;
122
123     case SIGHUP :
124         /* w/ a configuration file, we can force a re-read if we want */
125         reloadconfig = 1;
126         break;
127
128     default :
129         LOG(log_error, logtype_afpd, "afp_goaway: bad signal" );
130     }
131     return;
132 }
133
134 static void child_handler(int sig _U_)
135 {
136     server_child_handler(server_children);
137 }
138
139 int main(int ac, char **av)
140 {
141     AFPConfig           *config;
142     fd_set              rfds;
143     void                *ipc;
144     struct sigaction    sv;
145     sigset_t            sigs;
146     int                 ret;
147
148 #ifdef TRU64
149     argc = ac;
150     argv = av;
151     set_auth_parameters( ac, av );
152 #endif /* TRU64 */
153
154     /* Log SIGBUS/SIGSEGV SBT */
155     fault_setup(NULL);
156
157     /* Default log setup: log to syslog */
158     setuplog("default log_note");
159
160     afp_options_init(&default_options);
161     if (!afp_options_parse(ac, av, &default_options))
162         exit(EXITERR_CONF);
163
164     /* Save the user's current umask for use with CNID (and maybe some 
165      * other things, too). */
166     default_options.save_mask = umask( default_options.umask );
167
168     switch(server_lock("afpd", default_options.pidfile,
169                        default_options.flags & OPTION_DEBUG)) {
170     case -1: /* error */
171         exit(EXITERR_SYS);
172     case 0: /* child */
173         break;
174     default: /* server */
175         exit(0);
176     }
177
178     /* install child handler for asp and dsi. we do this before afp_goaway
179      * as afp_goaway references stuff from here. 
180      * XXX: this should really be setup after the initial connections. */
181     if (!(server_children = server_child_alloc(default_options.connections,
182                             CHILD_NFORKS))) {
183         LOG(log_error, logtype_afpd, "main: server_child alloc: %s", strerror(errno) );
184         afp_exit(EXITERR_SYS);
185     }
186
187     memset(&sv, 0, sizeof(sv));    
188 #ifdef AFP3x
189     /* linux at least up to 2.4.22 send a SIGXFZ for vfat fs,
190        even if the file is open with O_LARGEFILE ! */
191 #ifdef SIGXFSZ
192     sv.sa_handler = SIG_IGN;
193     sigemptyset( &sv.sa_mask );
194     if (sigaction(SIGXFSZ, &sv, NULL ) < 0 ) {
195         LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
196         afp_exit(EXITERR_SYS);
197     }
198 #endif
199 #endif
200     
201     sv.sa_handler = child_handler;
202     sigemptyset( &sv.sa_mask );
203     sigaddset(&sv.sa_mask, SIGALRM);
204     sigaddset(&sv.sa_mask, SIGHUP);
205     sigaddset(&sv.sa_mask, SIGTERM);
206     sigaddset(&sv.sa_mask, SIGUSR1);
207     
208     sv.sa_flags = SA_RESTART;
209     if ( sigaction( SIGCHLD, &sv, NULL ) < 0 ) {
210         LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
211         afp_exit(EXITERR_SYS);
212     }
213
214     sv.sa_handler = afp_goaway;
215     sigemptyset( &sv.sa_mask );
216     sigaddset(&sv.sa_mask, SIGALRM);
217     sigaddset(&sv.sa_mask, SIGTERM);
218     sigaddset(&sv.sa_mask, SIGHUP);
219     sigaddset(&sv.sa_mask, SIGCHLD);
220     sv.sa_flags = SA_RESTART;
221     if ( sigaction( SIGUSR1, &sv, NULL ) < 0 ) {
222         LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
223         afp_exit(EXITERR_SYS);
224     }
225
226     sigemptyset( &sv.sa_mask );
227     sigaddset(&sv.sa_mask, SIGALRM);
228     sigaddset(&sv.sa_mask, SIGTERM);
229     sigaddset(&sv.sa_mask, SIGUSR1);
230     sigaddset(&sv.sa_mask, SIGCHLD);
231     sv.sa_flags = SA_RESTART;
232     if ( sigaction( SIGHUP, &sv, NULL ) < 0 ) {
233         LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
234         afp_exit(EXITERR_SYS);
235     }
236
237
238     sigemptyset( &sv.sa_mask );
239     sigaddset(&sv.sa_mask, SIGALRM);
240     sigaddset(&sv.sa_mask, SIGHUP);
241     sigaddset(&sv.sa_mask, SIGUSR1);
242     sigaddset(&sv.sa_mask, SIGCHLD);
243     sv.sa_flags = SA_RESTART;
244     if ( sigaction( SIGTERM, &sv, NULL ) < 0 ) {
245         LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
246         afp_exit(EXITERR_SYS);
247     }
248
249     /* afpd.conf: not in config file: lockfile, connections, configfile
250      *            preference: command-line provides defaults.
251      *                        config file over-writes defaults.
252      *
253      * we also need to make sure that killing afpd during startup
254      * won't leave any lingering registered names around.
255      */
256
257     sigemptyset(&sigs);
258     sigaddset(&sigs, SIGALRM);
259     sigaddset(&sigs, SIGHUP);
260     sigaddset(&sigs, SIGUSR1);
261 #if 0
262     /* don't block SIGTERM */
263     sigaddset(&sigs, SIGTERM);
264 #endif
265     sigaddset(&sigs, SIGCHLD);
266
267     pthread_sigmask(SIG_BLOCK, &sigs, NULL);
268     if (!(configs = configinit(&default_options))) {
269         LOG(log_error, logtype_afpd, "main: no servers configured");
270         afp_exit(EXITERR_CONF);
271     }
272     pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
273
274     /* Initialize */
275     cnid_init();
276     if (rpc_init("127.0.0.1", 4701) != 0)
277         afp_exit(EXITERR_SYS);
278     
279     /* watch atp, dsi sockets and ipc parent/child file descriptor. */
280     if ((ipc = server_ipc_create())) {
281         Ipc_fd = server_ipc_parent(ipc);
282     }
283     set_fd(Ipc_fd);
284
285     /* wait for an appleshare connection. parent remains in the loop
286      * while the children get handled by afp_over_{asp,dsi}.  this is
287      * currently vulnerable to a denial-of-service attack if a
288      * connection is made without an actual login attempt being made
289      * afterwards. establishing timeouts for logins is a possible 
290      * solution. */
291     while (1) {
292         rfds = save_rfds;
293         pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
294         ret = select(FD_SETSIZE, &rfds, NULL, NULL, NULL);
295         pthread_sigmask(SIG_BLOCK, &sigs, NULL);
296         int saveerrno = errno;
297
298         if (reloadconfig) {
299             nologin++;
300             auth_unload();
301             AFPConfig *config;
302
303             LOG(log_info, logtype_afpd, "re-reading configuration file");
304             for (config = configs; config; config = config->next)
305                 if (config->server_cleanup)
306                     config->server_cleanup(config);
307
308             /* configfree close atp socket used for DDP tickle, there's an issue
309              * with atp tid. */
310             configfree(configs, NULL);
311             if (!(configs = configinit(&default_options))) {
312                 LOG(log_error, logtype_afpd, "config re-read: no servers configured");
313                 afp_exit(EXITERR_CONF);
314             }
315             set_fd(Ipc_fd);
316             nologin = 0;
317             reloadconfig = 0;
318             errno = saveerrno;
319         }
320         
321         if (ret < 0) {
322             if (errno == EINTR)
323                 continue;
324             LOG(log_error, logtype_afpd, "main: can't wait for input: %s", strerror(errno));
325             break;
326         }
327         if (Ipc_fd >=0 && FD_ISSET(Ipc_fd, &rfds)) {
328             server_ipc_read(server_children);
329         }
330         for (config = configs; config; config = config->next) {
331             if (config->fd < 0)
332                 continue;
333             if (FD_ISSET(config->fd, &rfds)) {
334                 config->server_start(config, configs, server_children);
335             }
336         }
337     }
338
339     return 0;
340 }