]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/main.c
Spotlight: use async Tracker SPARQL API
[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 <sys/poll.h>
19 #include <errno.h>
20 #include <sys/wait.h>
21 #include <sys/resource.h>
22
23 #include <atalk/logger.h>
24 #include <atalk/adouble.h>
25 #include <atalk/compat.h>
26 #include <atalk/dsi.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/globals.h>
34 #include <atalk/netatalk_conf.h>
35
36 #include "afp_config.h"
37 #include "status.h"
38 #include "fork.h"
39 #include "uam_auth.h"
40 #include "afp_zeroconf.h"
41 #include "afpstats.h"
42
43 #define ASEV_THRESHHOLD 10
44
45 unsigned char nologin = 0;
46
47 static AFPObj obj;
48 static server_child_t *server_children;
49 static sig_atomic_t reloadconfig = 0;
50 static sig_atomic_t gotsigchld = 0;
51 static struct asev *asev;
52
53 static afp_child_t *dsi_start(AFPObj *obj, DSI *dsi, server_child_t *server_children);
54
55 static void afp_exit(int ret)
56 {
57     exit(ret);
58 }
59
60
61 /* ------------------
62    initialize fd set we are waiting for.
63 */
64 static bool init_listening_sockets(const AFPObj *config)
65 {
66     DSI *dsi;
67     int numlisteners;
68
69     for (numlisteners = 0, dsi = config->dsi; dsi; dsi = dsi->next) {
70         numlisteners++;
71     }
72
73     asev = asev_init(config->options.connections + numlisteners + ASEV_THRESHHOLD);
74     if (asev == NULL) {
75         return false;
76     }
77
78     for (dsi = config->dsi; dsi; dsi = dsi->next) {
79         if (!(asev_add_fd(asev, dsi->serversock, LISTEN_FD, dsi))) {
80             return false;
81         }
82     }
83
84     return true;
85 }
86  
87 static bool reset_listening_sockets(const AFPObj *config)
88 {
89     const DSI *dsi;
90
91     for (dsi = config->dsi; dsi; dsi = dsi->next) {
92         if (!(asev_del_fd(asev, dsi->serversock))) {
93             return false;
94         }
95     }
96     return true;
97 }
98
99 /* ------------------ */
100 static void afp_goaway(int sig)
101 {
102     switch( sig ) {
103
104     case SIGTERM:
105     case SIGQUIT:
106         LOG(log_note, logtype_afpd, "AFP Server shutting down");
107         if (server_children)
108             server_child_kill(server_children, SIGTERM);
109         _exit(0);
110         break;
111
112     case SIGUSR1 :
113         nologin++;
114         auth_unload();
115         LOG(log_info, logtype_afpd, "disallowing logins");        
116
117         if (server_children)
118             server_child_kill(server_children, sig);
119         break;
120
121     case SIGHUP :
122         /* w/ a configuration file, we can force a re-read if we want */
123         reloadconfig = 1;
124         break;
125
126     case SIGCHLD:
127         /* w/ a configuration file, we can force a re-read if we want */
128         gotsigchld = 1;
129         break;
130
131     default :
132         LOG(log_error, logtype_afpd, "afp_goaway: bad signal" );
133     }
134     return;
135 }
136
137 static void child_handler(void)
138 {
139     int fd;
140     int status;
141     pid_t pid;
142   
143 #ifndef WAIT_ANY
144 #define WAIT_ANY (-1)
145 #endif /* ! WAIT_ANY */
146
147     while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) > 0) {
148         if (WIFEXITED(status)) {
149             if (WEXITSTATUS(status))
150                 LOG(log_info, logtype_afpd, "child[%d]: exited %d", pid, WEXITSTATUS(status));
151             else
152                 LOG(log_info, logtype_afpd, "child[%d]: done", pid);
153         } else {
154             if (WIFSIGNALED(status))
155                 LOG(log_info, logtype_afpd, "child[%d]: killed by signal %d", pid, WTERMSIG(status));
156             else
157                 LOG(log_info, logtype_afpd, "child[%d]: died", pid);
158         }
159
160         fd = server_child_remove(server_children, pid);
161         if (fd == -1) {
162             continue;
163         }
164         if (!(asev_del_fd(asev, fd))) {
165             LOG(log_error, logtype_afpd, "child[%d]: asev_del_fd: %d", pid, fd);
166         }
167     }
168 }
169
170 static int setlimits(void)
171 {
172     struct rlimit rlim;
173
174     if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
175         LOG(log_warning, logtype_afpd, "setlimits: reading current limits failed: %s", strerror(errno));
176         return -1;
177     }
178     if (rlim.rlim_cur != RLIM_INFINITY && rlim.rlim_cur < 65535) {
179         rlim.rlim_cur = 65535;
180         if (rlim.rlim_max != RLIM_INFINITY && rlim.rlim_max < 65535)
181             rlim.rlim_max = 65535;
182         if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
183             LOG(log_warning, logtype_afpd, "setlimits: increasing limits failed: %s", strerror(errno));
184             return -1;
185         }
186     }
187     return 0;
188 }
189
190 int main(int ac, char **av)
191 {
192     struct sigaction    sv;
193     sigset_t            sigs;
194     int                 ret;
195
196     /* Parse argv args and initialize default options */
197     afp_options_parse_cmdline(&obj, ac, av);
198
199     if (!(obj.cmdlineflags & OPTION_DEBUG) && (daemonize(0, 0) != 0))
200         exit(EXITERR_SYS);
201
202     /* Log SIGBUS/SIGSEGV SBT */
203     fault_setup(NULL);
204
205     if (afp_config_parse(&obj, "afpd") != 0)
206         afp_exit(EXITERR_CONF);
207
208     /* Save the user's current umask */
209     obj.options.save_mask = umask(obj.options.umask);
210
211     /* install child handler for asp and dsi. we do this before afp_goaway
212      * as afp_goaway references stuff from here. 
213      * XXX: this should really be setup after the initial connections. */
214     if (!(server_children = server_child_alloc(obj.options.connections))) {
215         LOG(log_error, logtype_afpd, "main: server_child alloc: %s", strerror(errno) );
216         afp_exit(EXITERR_SYS);
217     }
218     
219     sigemptyset(&sigs);
220     pthread_sigmask(SIG_SETMASK, &sigs, NULL);
221
222     memset(&sv, 0, sizeof(sv));    
223     /* linux at least up to 2.4.22 send a SIGXFZ for vfat fs,
224        even if the file is open with O_LARGEFILE ! */
225 #ifdef SIGXFSZ
226     sv.sa_handler = SIG_IGN;
227     sigemptyset( &sv.sa_mask );
228     if (sigaction(SIGXFSZ, &sv, NULL ) < 0 ) {
229         LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
230         afp_exit(EXITERR_SYS);
231     }
232 #endif
233
234     sv.sa_handler = SIG_IGN;
235     sigemptyset( &sv.sa_mask );
236     if (sigaction(SIGPIPE, &sv, NULL ) < 0 ) {
237         LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
238         afp_exit(EXITERR_SYS);
239     }
240     
241     sv.sa_handler = afp_goaway; /* handler for all sigs */
242
243     sigemptyset( &sv.sa_mask );
244     sigaddset(&sv.sa_mask, SIGALRM);
245     sigaddset(&sv.sa_mask, SIGHUP);
246     sigaddset(&sv.sa_mask, SIGTERM);
247     sigaddset(&sv.sa_mask, SIGUSR1);
248     sigaddset(&sv.sa_mask, SIGQUIT);    
249     sv.sa_flags = SA_RESTART;
250     if ( sigaction( SIGCHLD, &sv, NULL ) < 0 ) {
251         LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
252         afp_exit(EXITERR_SYS);
253     }
254
255     sigemptyset( &sv.sa_mask );
256     sigaddset(&sv.sa_mask, SIGALRM);
257     sigaddset(&sv.sa_mask, SIGTERM);
258     sigaddset(&sv.sa_mask, SIGHUP);
259     sigaddset(&sv.sa_mask, SIGCHLD);
260     sigaddset(&sv.sa_mask, SIGQUIT);
261     sv.sa_flags = SA_RESTART;
262     if ( sigaction( SIGUSR1, &sv, NULL ) < 0 ) {
263         LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
264         afp_exit(EXITERR_SYS);
265     }
266
267     sigemptyset( &sv.sa_mask );
268     sigaddset(&sv.sa_mask, SIGALRM);
269     sigaddset(&sv.sa_mask, SIGTERM);
270     sigaddset(&sv.sa_mask, SIGUSR1);
271     sigaddset(&sv.sa_mask, SIGCHLD);
272     sigaddset(&sv.sa_mask, SIGQUIT);
273     sv.sa_flags = SA_RESTART;
274     if ( sigaction( SIGHUP, &sv, NULL ) < 0 ) {
275         LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
276         afp_exit(EXITERR_SYS);
277     }
278
279     sigemptyset( &sv.sa_mask );
280     sigaddset(&sv.sa_mask, SIGALRM);
281     sigaddset(&sv.sa_mask, SIGHUP);
282     sigaddset(&sv.sa_mask, SIGUSR1);
283     sigaddset(&sv.sa_mask, SIGCHLD);
284     sigaddset(&sv.sa_mask, SIGQUIT);
285     sv.sa_flags = SA_RESTART;
286     if ( sigaction( SIGTERM, &sv, NULL ) < 0 ) {
287         LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
288         afp_exit(EXITERR_SYS);
289     }
290
291     sigemptyset( &sv.sa_mask );
292     sigaddset(&sv.sa_mask, SIGALRM);
293     sigaddset(&sv.sa_mask, SIGHUP);
294     sigaddset(&sv.sa_mask, SIGUSR1);
295     sigaddset(&sv.sa_mask, SIGCHLD);
296     sigaddset(&sv.sa_mask, SIGTERM);
297     sv.sa_flags = SA_RESTART;
298     if (sigaction(SIGQUIT, &sv, NULL ) < 0 ) {
299         LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
300         afp_exit(EXITERR_SYS);
301     }
302
303     /* afp.conf:  not in config file: lockfile, configfile
304      *            preference: command-line provides defaults.
305      *                        config file over-writes defaults.
306      *
307      * we also need to make sure that killing afpd during startup
308      * won't leave any lingering registered names around.
309      */
310
311     sigemptyset(&sigs);
312     sigaddset(&sigs, SIGALRM);
313     sigaddset(&sigs, SIGHUP);
314     sigaddset(&sigs, SIGUSR1);
315 #if 0
316     /* don't block SIGTERM */
317     sigaddset(&sigs, SIGTERM);
318 #endif
319     sigaddset(&sigs, SIGCHLD);
320
321     pthread_sigmask(SIG_BLOCK, &sigs, NULL);
322 #ifdef HAVE_DBUS_GLIB
323     /* Run dbus AFP statics thread */
324     if (obj.options.flags & OPTION_DBUS_AFPSTATS)
325         (void)afpstats_init(server_children);
326 #endif
327     if (configinit(&obj) != 0) {
328         LOG(log_error, logtype_afpd, "main: no servers configured");
329         afp_exit(EXITERR_CONF);
330     }
331     pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
332
333     /* Initialize */
334     cnid_init();
335
336     /* watch atp, dsi sockets and ipc parent/child file descriptor. */
337     if (!(init_listening_sockets(&obj))) {
338         LOG(log_error, logtype_afpd, "main: couldn't initialize socket handler");
339         afp_exit(EXITERR_CONF);
340     }
341
342     /* set limits */
343     (void)setlimits();
344
345     afp_child_t *child;
346     int saveerrno;
347
348     /* wait for an appleshare connection. parent remains in the loop
349      * while the children get handled by afp_over_{asp,dsi}.  this is
350      * currently vulnerable to a denial-of-service attack if a
351      * connection is made without an actual login attempt being made
352      * afterwards. establishing timeouts for logins is a possible 
353      * solution. */
354     while (1) {
355         pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
356         ret = poll(asev->fdset, asev->used, -1);
357         pthread_sigmask(SIG_BLOCK, &sigs, NULL);
358         saveerrno = errno;
359
360         if (gotsigchld) {
361             gotsigchld = 0;
362             child_handler();
363             continue;
364         }
365
366         if (reloadconfig) {
367             nologin++;
368
369             if (!(reset_listening_sockets(&obj))) {
370                 LOG(log_error, logtype_afpd, "main: reset socket handlers");
371                 afp_exit(EXITERR_CONF);
372             }
373
374             LOG(log_info, logtype_afpd, "re-reading configuration file");
375
376             configfree(&obj, NULL);
377             afp_config_free(&obj);
378
379             if (afp_config_parse(&obj, "afpd") != 0)
380                 afp_exit(EXITERR_CONF);
381
382             if (configinit(&obj) != 0) {
383                 LOG(log_error, logtype_afpd, "config re-read: no servers configured");
384                 afp_exit(EXITERR_CONF);
385             }
386
387             if (!(init_listening_sockets(&obj))) {
388                 LOG(log_error, logtype_afpd, "main: couldn't initialize socket handler");
389                 afp_exit(EXITERR_CONF);
390             }
391
392             nologin = 0;
393             reloadconfig = 0;
394             errno = saveerrno;
395             continue;
396         }
397
398         if (ret == 0)
399             continue;
400         
401         if (ret < 0) {
402             if (errno == EINTR)
403                 continue;
404             LOG(log_error, logtype_afpd, "main: can't wait for input: %s", strerror(errno));
405             break;
406         }
407
408         for (int i = 0; i < asev->used; i++) {
409             if (asev->fdset[i].revents & (POLLIN | POLLERR | POLLHUP | POLLNVAL)) {
410                 switch (asev->data[i].fdtype) {
411
412                 case LISTEN_FD:
413                     if ((child = dsi_start(&obj, (DSI *)(asev->data[i].private), server_children))) {
414                         if (!(asev_add_fd(asev, child->afpch_ipc_fd, IPC_FD, child))) {
415                             LOG(log_error, logtype_afpd, "out of asev slots");
416
417                             /*
418                              * Close IPC fd here and mark it as unused
419                              */
420                             close(child->afpch_ipc_fd);
421                             child->afpch_ipc_fd = -1;
422
423                             /*
424                              * Being unfriendly here, but we really
425                              * want to get rid of it. The 'child'
426                              * handle gets cleaned up in the SIGCLD
427                              * handler.
428                              */
429                             kill(child->afpch_pid, SIGKILL);
430                         }
431                     }
432                     break;
433
434                 case IPC_FD:
435                     child = (afp_child_t *)(asev->data[i].private);
436                     LOG(log_debug, logtype_afpd, "main: IPC request from child[%u]", child->afpch_pid);
437
438                     if (ipc_server_read(server_children, child->afpch_ipc_fd) != 0) {
439                         if (!(asev_del_fd(asev, child->afpch_ipc_fd))) {
440                             LOG(log_error, logtype_afpd, "child[%u]: no IPC fd");
441                         }
442                         close(child->afpch_ipc_fd);
443                         child->afpch_ipc_fd = -1;
444                     }
445                     break;
446
447                 default:
448                     LOG(log_debug, logtype_afpd, "main: IPC request for unknown type");
449                     break;
450                 } /* switch */
451             }  /* if */
452         } /* for (i)*/
453     } /* while (1) */
454
455     return 0;
456 }
457
458 static afp_child_t *dsi_start(AFPObj *obj, DSI *dsi, server_child_t *server_children)
459 {
460     afp_child_t *child = NULL;
461
462     if (dsi_getsession(dsi, server_children, obj->options.tickleval, &child) != 0) {
463         LOG(log_error, logtype_afpd, "dsi_start: session error: %s", strerror(errno));
464         return NULL;
465     }
466
467     /* we've forked. */
468     if (child == NULL) {
469         configfree(obj, dsi);
470         afp_over_dsi(obj); /* start a session */
471         exit (0);
472     }
473
474     return child;
475 }