2 * Copyright (c) 1990,1993 Regents of The University of Michigan.
3 * All Rights Reserved. See COPYRIGHT.
8 #endif /* HAVE_CONFIG_H */
14 #include <sys/param.h>
17 #include <sys/socket.h>
21 #include <sys/resource.h>
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>
36 #include "afp_config.h"
42 #define ASEV_THRESHHOLD 10
44 unsigned char nologin = 0;
47 static server_child_t *server_children;
48 static sig_atomic_t reloadconfig = 0;
49 static sig_atomic_t gotsigchld = 0;
50 static struct asev *asev;
52 static afp_child_t *dsi_start(AFPObj *obj, DSI *dsi, server_child_t *server_children);
54 static void afp_exit(int ret)
61 initialize fd set we are waiting for.
63 static bool init_listening_sockets(const AFPObj *config)
68 for (numlisteners = 0, dsi = config->dsi; dsi; dsi = dsi->next) {
72 asev = asev_init(config->options.connections + numlisteners + ASEV_THRESHHOLD);
77 for (dsi = config->dsi; dsi; dsi = dsi->next) {
78 if (!(asev_add_fd(asev, dsi->serversock, LISTEN_FD, dsi))) {
86 static bool reset_listening_sockets(const AFPObj *config)
90 for (dsi = config->dsi; dsi; dsi = dsi->next) {
91 if (!(asev_del_fd(asev, dsi->serversock))) {
98 /* ------------------ */
99 static void afp_goaway(int sig)
105 LOG(log_note, logtype_afpd, "AFP Server shutting down");
107 server_child_kill(server_children, SIGTERM);
114 LOG(log_info, logtype_afpd, "disallowing logins");
117 server_child_kill(server_children, sig);
121 /* w/ a configuration file, we can force a re-read if we want */
126 /* w/ a configuration file, we can force a re-read if we want */
131 LOG(log_error, logtype_afpd, "afp_goaway: bad signal" );
136 static void child_handler(void)
143 #define WAIT_ANY (-1)
144 #endif /* ! WAIT_ANY */
146 while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) > 0) {
147 if (WIFEXITED(status)) {
148 if (WEXITSTATUS(status))
149 LOG(log_info, logtype_afpd, "child[%d]: exited %d", pid, WEXITSTATUS(status));
151 LOG(log_info, logtype_afpd, "child[%d]: done", pid);
153 if (WIFSIGNALED(status))
154 LOG(log_info, logtype_afpd, "child[%d]: killed by signal %d", pid, WTERMSIG(status));
156 LOG(log_info, logtype_afpd, "child[%d]: died", pid);
159 fd = server_child_remove(server_children, pid);
163 if (!(asev_del_fd(asev, fd))) {
164 LOG(log_error, logtype_afpd, "child[%d]: asev_del_fd: %d", pid, fd);
169 static int setlimits(void)
173 if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
174 LOG(log_warning, logtype_afpd, "setlimits: reading current limits failed: %s", strerror(errno));
177 if (rlim.rlim_cur != RLIM_INFINITY && rlim.rlim_cur < 65535) {
178 rlim.rlim_cur = 65535;
179 if (rlim.rlim_max != RLIM_INFINITY && rlim.rlim_max < 65535)
180 rlim.rlim_max = 65535;
181 if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
182 LOG(log_warning, logtype_afpd, "setlimits: increasing limits failed: %s", strerror(errno));
189 int main(int ac, char **av)
195 /* Parse argv args and initialize default options */
196 afp_options_parse_cmdline(&obj, ac, av);
198 if (!(obj.cmdlineflags & OPTION_DEBUG) && (daemonize(0, 0) != 0))
201 /* Log SIGBUS/SIGSEGV SBT */
204 if (afp_config_parse(&obj, "afpd") != 0)
205 afp_exit(EXITERR_CONF);
207 /* Save the user's current umask */
208 obj.options.save_mask = umask(obj.options.umask);
210 /* install child handler for asp and dsi. we do this before afp_goaway
211 * as afp_goaway references stuff from here.
212 * XXX: this should really be setup after the initial connections. */
213 if (!(server_children = server_child_alloc(obj.options.connections))) {
214 LOG(log_error, logtype_afpd, "main: server_child alloc: %s", strerror(errno) );
215 afp_exit(EXITERR_SYS);
219 pthread_sigmask(SIG_SETMASK, &sigs, NULL);
221 memset(&sv, 0, sizeof(sv));
222 /* linux at least up to 2.4.22 send a SIGXFZ for vfat fs,
223 even if the file is open with O_LARGEFILE ! */
225 sv.sa_handler = SIG_IGN;
226 sigemptyset( &sv.sa_mask );
227 if (sigaction(SIGXFSZ, &sv, NULL ) < 0 ) {
228 LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
229 afp_exit(EXITERR_SYS);
233 sv.sa_handler = SIG_IGN;
234 sigemptyset( &sv.sa_mask );
235 if (sigaction(SIGPIPE, &sv, NULL ) < 0 ) {
236 LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
237 afp_exit(EXITERR_SYS);
240 sv.sa_handler = afp_goaway; /* handler for all sigs */
242 sigemptyset( &sv.sa_mask );
243 sigaddset(&sv.sa_mask, SIGALRM);
244 sigaddset(&sv.sa_mask, SIGHUP);
245 sigaddset(&sv.sa_mask, SIGTERM);
246 sigaddset(&sv.sa_mask, SIGUSR1);
247 sigaddset(&sv.sa_mask, SIGQUIT);
248 sv.sa_flags = SA_RESTART;
249 if ( sigaction( SIGCHLD, &sv, NULL ) < 0 ) {
250 LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
251 afp_exit(EXITERR_SYS);
254 sigemptyset( &sv.sa_mask );
255 sigaddset(&sv.sa_mask, SIGALRM);
256 sigaddset(&sv.sa_mask, SIGTERM);
257 sigaddset(&sv.sa_mask, SIGHUP);
258 sigaddset(&sv.sa_mask, SIGCHLD);
259 sigaddset(&sv.sa_mask, SIGQUIT);
260 sv.sa_flags = SA_RESTART;
261 if ( sigaction( SIGUSR1, &sv, NULL ) < 0 ) {
262 LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
263 afp_exit(EXITERR_SYS);
266 sigemptyset( &sv.sa_mask );
267 sigaddset(&sv.sa_mask, SIGALRM);
268 sigaddset(&sv.sa_mask, SIGTERM);
269 sigaddset(&sv.sa_mask, SIGUSR1);
270 sigaddset(&sv.sa_mask, SIGCHLD);
271 sigaddset(&sv.sa_mask, SIGQUIT);
272 sv.sa_flags = SA_RESTART;
273 if ( sigaction( SIGHUP, &sv, NULL ) < 0 ) {
274 LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
275 afp_exit(EXITERR_SYS);
278 sigemptyset( &sv.sa_mask );
279 sigaddset(&sv.sa_mask, SIGALRM);
280 sigaddset(&sv.sa_mask, SIGHUP);
281 sigaddset(&sv.sa_mask, SIGUSR1);
282 sigaddset(&sv.sa_mask, SIGCHLD);
283 sigaddset(&sv.sa_mask, SIGQUIT);
284 sv.sa_flags = SA_RESTART;
285 if ( sigaction( SIGTERM, &sv, NULL ) < 0 ) {
286 LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
287 afp_exit(EXITERR_SYS);
290 sigemptyset( &sv.sa_mask );
291 sigaddset(&sv.sa_mask, SIGALRM);
292 sigaddset(&sv.sa_mask, SIGHUP);
293 sigaddset(&sv.sa_mask, SIGUSR1);
294 sigaddset(&sv.sa_mask, SIGCHLD);
295 sigaddset(&sv.sa_mask, SIGTERM);
296 sv.sa_flags = SA_RESTART;
297 if (sigaction(SIGQUIT, &sv, NULL ) < 0 ) {
298 LOG(log_error, logtype_afpd, "main: sigaction: %s", strerror(errno) );
299 afp_exit(EXITERR_SYS);
302 /* afp.conf: not in config file: lockfile, configfile
303 * preference: command-line provides defaults.
304 * config file over-writes defaults.
306 * we also need to make sure that killing afpd during startup
307 * won't leave any lingering registered names around.
311 sigaddset(&sigs, SIGALRM);
312 sigaddset(&sigs, SIGHUP);
313 sigaddset(&sigs, SIGUSR1);
315 /* don't block SIGTERM */
316 sigaddset(&sigs, SIGTERM);
318 sigaddset(&sigs, SIGCHLD);
320 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
321 #ifdef HAVE_DBUS_GLIB
322 /* Run dbus AFP statics thread */
323 if (obj.options.flags & OPTION_DBUS_AFPSTATS)
324 (void)afpstats_init(server_children);
326 if (configinit(&obj) != 0) {
327 LOG(log_error, logtype_afpd, "main: no servers configured");
328 afp_exit(EXITERR_CONF);
330 pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
335 /* watch atp, dsi sockets and ipc parent/child file descriptor. */
336 if (!(init_listening_sockets(&obj))) {
337 LOG(log_error, logtype_afpd, "main: couldn't initialize socket handler");
338 afp_exit(EXITERR_CONF);
347 /* wait for an appleshare connection. parent remains in the loop
348 * while the children get handled by afp_over_{asp,dsi}. this is
349 * currently vulnerable to a denial-of-service attack if a
350 * connection is made without an actual login attempt being made
351 * afterwards. establishing timeouts for logins is a possible
354 pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
355 ret = poll(asev->fdset, asev->used, -1);
356 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
368 if (!(reset_listening_sockets(&obj))) {
369 LOG(log_error, logtype_afpd, "main: reset socket handlers");
370 afp_exit(EXITERR_CONF);
373 LOG(log_info, logtype_afpd, "re-reading configuration file");
375 configfree(&obj, NULL);
376 afp_config_free(&obj);
378 if (afp_config_parse(&obj, "afpd") != 0)
379 afp_exit(EXITERR_CONF);
381 if (configinit(&obj) != 0) {
382 LOG(log_error, logtype_afpd, "config re-read: no servers configured");
383 afp_exit(EXITERR_CONF);
386 if (!(init_listening_sockets(&obj))) {
387 LOG(log_error, logtype_afpd, "main: couldn't initialize socket handler");
388 afp_exit(EXITERR_CONF);
395 if (server_children) {
396 server_child_kill(server_children, SIGHUP);
408 LOG(log_error, logtype_afpd, "main: can't wait for input: %s", strerror(errno));
412 for (int i = 0; i < asev->used; i++) {
413 if (asev->fdset[i].revents & (POLLIN | POLLERR | POLLHUP | POLLNVAL)) {
414 switch (asev->data[i].fdtype) {
417 if ((child = dsi_start(&obj, (DSI *)(asev->data[i].private), server_children))) {
418 if (!(asev_add_fd(asev, child->afpch_ipc_fd, IPC_FD, child))) {
419 LOG(log_error, logtype_afpd, "out of asev slots");
422 * Close IPC fd here and mark it as unused
424 close(child->afpch_ipc_fd);
425 child->afpch_ipc_fd = -1;
428 * Being unfriendly here, but we really
429 * want to get rid of it. The 'child'
430 * handle gets cleaned up in the SIGCLD
433 kill(child->afpch_pid, SIGKILL);
439 child = (afp_child_t *)(asev->data[i].private);
440 LOG(log_debug, logtype_afpd, "main: IPC request from child[%u]", child->afpch_pid);
442 if (ipc_server_read(server_children, child->afpch_ipc_fd) != 0) {
443 if (!(asev_del_fd(asev, child->afpch_ipc_fd))) {
444 LOG(log_error, logtype_afpd, "child[%u]: no IPC fd");
446 close(child->afpch_ipc_fd);
447 child->afpch_ipc_fd = -1;
452 LOG(log_debug, logtype_afpd, "main: IPC request for unknown type");
462 static afp_child_t *dsi_start(AFPObj *obj, DSI *dsi, server_child_t *server_children)
464 afp_child_t *child = NULL;
466 if (dsi_getsession(dsi, server_children, obj->options.tickleval, &child) != 0) {
467 LOG(log_error, logtype_afpd, "dsi_start: session error: %s", strerror(errno));
473 configfree(obj, dsi);
474 afp_over_dsi(obj); /* start a session */