1 /* service.c -- skeleton for Cyrus service; calls the real main
2  *
3  * Copyright (c) 1994-2008 Carnegie Mellon University.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in
14  *    the documentation and/or other materials provided with the
15  *    distribution.
16  *
17  * 3. The name "Carnegie Mellon University" must not be used to
18  *    endorse or promote products derived from this software without
19  *    prior written permission. For permission or any legal
20  *    details, please contact
21  *      Carnegie Mellon University
22  *      Center for Technology Transfer and Enterprise Creation
23  *      4615 Forbes Avenue
24  *      Suite 302
25  *      Pittsburgh, PA  15213
26  *      (412) 268-7393, fax: (412) 268-7395
27  *      innovation@andrew.cmu.edu
28  *
29  * 4. Redistributions of any form whatsoever must retain the following
30  *    acknowledgment:
31  *    "This product includes software developed by Computing Services
32  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
33  *
34  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
35  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
36  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
37  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
38  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
39  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
40  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
41  */
42 
43 #include <config.h>
44 
45 #include <stdio.h>
46 #include <sys/time.h>
47 #include <sys/types.h>
48 #include <sys/wait.h>
49 #ifdef HAVE_UNISTD_H
50 #include <unistd.h>
51 #endif
52 #include <fcntl.h>
53 #include <signal.h>
54 #include <sys/param.h>
55 #include <sys/stat.h>
56 #include <syslog.h>
57 #include <netdb.h>
58 #include <sys/socket.h>
59 #include <netinet/in.h>
60 #include <netinet/tcp.h>
61 #include <arpa/inet.h>
62 #include <errno.h>
63 #include <stdlib.h>
64 #include <sysexits.h>
65 #include <string.h>
66 #include <limits.h>
67 
68 #include "service.h"
69 #include "libconfig.h"
70 #include "xmalloc.h"
71 #include "xstrlcpy.h"
72 #include "strarray.h"
73 #include "signals.h"
74 #include "util.h"
75 
76 #ifndef PATH_MAX
77 #define PATH_MAX 4096
78 #endif
79 
80 extern int optind, opterr;
81 extern char *optarg;
82 
83 /* number of times this service has been used */
84 static int use_count = 0;
85 static int verbose = 0;
86 static int lockfd = -1;
87 static int newfile = 0;
88 
notify_master(int fd,int msg)89 void notify_master(int fd, int msg)
90 {
91     struct notify_message notifymsg;
92     if (verbose) syslog(LOG_DEBUG, "telling master %x", msg);
93     notifymsg.message = msg;
94     notifymsg.service_pid = getpid();
95     if (write(fd, &notifymsg, sizeof(notifymsg)) != sizeof(notifymsg)) {
96         syslog(LOG_ERR, "unable to tell master %x: %m", msg);
97     }
98 }
99 
100 #ifdef HAVE_LIBWRAP
101 #include <tcpd.h>
102 
103 int allow_severity = LOG_DEBUG;
104 int deny_severity = LOG_ERR;
105 
libwrap_init(struct request_info * req,char * service)106 static void libwrap_init(struct request_info *req, char *service)
107 {
108     request_init(req, RQ_DAEMON, service, 0);
109 }
110 
libwrap_ask(struct request_info * req,int fd)111 static int libwrap_ask(struct request_info *req, int fd)
112 {
113     struct sockaddr_storage sin_storage;
114     struct sockaddr *sin = (struct sockaddr *)&sin_storage;
115     socklen_t sinlen;
116     int a;
117 
118     /* XXX: old FreeBSD didn't fill sockaddr correctly against AF_UNIX */
119     sin->sa_family = AF_UNIX;
120 
121     /* is this a connection from the local host? */
122     sinlen = sizeof(struct sockaddr_storage);
123     if (getpeername(fd, sin, &sinlen) == 0) {
124         if (sin->sa_family == AF_UNIX) {
125             return 1;
126         }
127     }
128 
129     /* i hope using the sock_* functions are legal; it certainly makes
130        this code very easy! */
131     request_set(req, RQ_FILE, fd, 0);
132     sock_host(req);
133 
134     a = hosts_access(req);
135     if (!a) {
136         syslog(deny_severity, "refused connection from %s", eval_client(req));
137     }
138 
139     return a;
140 }
141 
142 #else
143 struct request_info { int x; };
144 
libwrap_init(struct request_info * r,char * service)145 static void libwrap_init(struct request_info *r __attribute__((unused)),
146                          char *service __attribute__((unused)))
147 {
148 
149 }
150 
libwrap_ask(struct request_info * r,int fd)151 static int libwrap_ask(struct request_info *r __attribute__((unused)),
152                        int fd __attribute__((unused)))
153 {
154     return 1;
155 }
156 
157 #endif
158 
159 extern void cyrus_init(const char *, const char *, unsigned, int);
160 
getlockfd(char * service,int id)161 static int getlockfd(char *service, int id)
162 {
163     char lockfile[1024];
164     int fd;
165 
166     snprintf(lockfile, sizeof(lockfile), "%s/socket/%s-%d.lock",
167              config_dir, service, id);
168     fd = open(lockfile, O_CREAT | O_RDWR, 0600);
169     if (fd < 0) {
170         syslog(LOG_ERR,
171                "locking disabled: couldn't open socket lockfile %s: %m",
172                lockfile);
173         lockfd = -1;
174         return -1;
175     }
176 
177     lockfd = fd;
178     return 0;
179 }
180 
lockaccept(void)181 static int lockaccept(void)
182 {
183     struct flock alockinfo;
184     int rc;
185 
186     /* setup the alockinfo structure */
187     alockinfo.l_start = 0;
188     alockinfo.l_len = 0;
189     alockinfo.l_whence = SEEK_SET;
190 
191     if (lockfd != -1) {
192         alockinfo.l_type = F_WRLCK;
193         while ((rc = fcntl(lockfd, F_SETLKW, &alockinfo)) < 0 &&
194                errno == EINTR &&
195                !signals_poll())
196             /* noop */;
197 
198         if (rc < 0 && signals_poll()) {
199             if (MESSAGE_MASTER_ON_EXIT)
200                 notify_master(STATUS_FD, MASTER_SERVICE_UNAVAILABLE);
201             service_abort(0);
202             return -1;
203         }
204 
205         if (rc < 0) {
206             syslog(LOG_ERR, "fcntl: F_SETLKW: error getting accept lock: %m");
207             if (MESSAGE_MASTER_ON_EXIT)
208                 notify_master(STATUS_FD, MASTER_SERVICE_UNAVAILABLE);
209             service_abort(EX_OSERR);
210             return -1;
211         }
212     }
213 
214     return 0;
215 }
216 
unlockaccept(void)217 static int unlockaccept(void)
218 {
219     struct flock alockinfo;
220     int rc;
221 
222     /* setup the alockinfo structure */
223     alockinfo.l_start = 0;
224     alockinfo.l_len = 0;
225     alockinfo.l_whence = SEEK_SET;
226 
227     if (lockfd != -1) {
228         alockinfo.l_type = F_UNLCK;
229         while ((rc = fcntl(lockfd, F_SETLKW, &alockinfo)) < 0 &&
230                errno == EINTR && !signals_poll())
231             /* noop */;
232 
233         if (rc < 0) {
234             syslog(LOG_ERR,
235                    "fcntl: F_SETLKW: error releasing accept lock: %m");
236             if (MESSAGE_MASTER_ON_EXIT)
237                 notify_master(STATUS_FD, MASTER_SERVICE_UNAVAILABLE);
238             service_abort(EX_OSERR);
239             return -1;
240         }
241     }
242 
243     return 0;
244 }
245 
safe_wait_readable(int fd)246 static int safe_wait_readable(int fd)
247 {
248     fd_set rfds;
249     int r;
250 
251     FD_ZERO(&rfds);
252     FD_SET(fd, &rfds);
253 
254     /* Waiting for incoming connection, we want to leave as soon as
255      * possible upon SIGHUP. Julien explains:
256      *
257      * The thing is SIGHUP handler is set as restartable, which is a good thing
258      * when we have received a connection and are processing client commands:
259      * we don't want to be interrupted by that signal.
260      *
261      * On the other hand, when we are waiting to receive a new connection, I
262      * needed a way to make the service instance holding the lock react faster.
263      * Without resetting SIGHUP as not restartable, the instance would just
264      * keep on waiting for a new connection (while the other instances -
265      * waiting for the lock - had received and processed the signal right
266      * away).
267      *
268      * Now that we have safe_wait_readable, Linux systems already react faster
269      * because there select/pselect always returns -1/EINTR even if SA_RESTART
270      * is set. But that may not be the case in other OSes (POSIX spec says it
271      * is implementation-defined whether it does restart or return -1/EINTR
272      * when SA_RESTART is set).
273      */
274     signals_reset_sighup_handler(0);
275 
276     r = signals_select(fd+1, &rfds, NULL, NULL, NULL);
277 
278     /* we don't want to be interrupted by SIGHUP anymore */
279     signals_reset_sighup_handler(1);
280 
281     return r;
282 }
283 
main(int argc,char ** argv,char ** envp)284 int main(int argc, char **argv, char **envp)
285 {
286     int fdflags;
287     int fd;
288     char *p = NULL, *service;
289     struct request_info request;
290     int opt;
291     char *alt_config = NULL;
292     int call_debugger = 0;
293     int debug_stdio = 0;
294     int max_use = MAX_USE;
295     int reuse_timeout = REUSE_TIMEOUT;
296     int soctype;
297     socklen_t typelen = sizeof(soctype);
298     struct sockaddr socname;
299     socklen_t addrlen = sizeof(struct sockaddr);
300     int id;
301     char path[PATH_MAX];
302     struct stat sbuf;
303     ino_t start_ino;
304     off_t start_size;
305     time_t start_mtime;
306 
307     /*
308      * service_init and service_main need argv and argc, so they can process
309      * service-specific options.  They need argv[0] to point into the real argv
310      * memory space, so that setproctitle can work its magic.  But they also
311      * need the generic options handled here to be removed, because they don't
312      * know how to handle them.
313      *
314      * So, we create a strarray_t "service_argv", and populate it with the
315      * options that we aren't handling here, using strarray_appendm (which
316      * simply ptr-copies its argument), and pass that through, and everything
317      * is happy.
318      *
319      * Note that we don't need to strarray_free service_argv, because it
320      * doesn't contain any malloced memory.
321      */
322     strarray_t service_argv = STRARRAY_INITIALIZER;
323     strarray_appendm(&service_argv, argv[0]);
324 
325     opterr = 0; /* disable error reporting,
326                    since we don't know about service-specific options */
327     while ((opt = getopt(argc, argv, "C:U:T:DX")) != EOF) {
328         if (argv[optind-1][0] == '-' && strlen(argv[optind-1]) > 2) {
329             /* we have merged options */
330             syslog(LOG_ERR,
331                    "options and arguments MUST be separated by whitespace");
332             exit(EX_USAGE);
333         }
334 
335         switch (opt) {
336         case 'C': /* alt config file */
337             alt_config = optarg;
338             break;
339         case 'U': /* maximum uses */
340             max_use = atoi(optarg);
341             if (max_use < 0) max_use = 0;
342             break;
343         case 'T': /* reuse timeout */
344             reuse_timeout = atoi(optarg);
345             if (reuse_timeout < 0) reuse_timeout = 0;
346             break;
347         case 'D':
348             call_debugger = 1;
349             break;
350         case 'X':
351             debug_stdio = 1;
352             break;
353         default:
354             strarray_appendm(&service_argv, argv[optind-1]);
355 
356             /* option has an argument */
357             if (optind < argc && argv[optind][0] != '-')
358                 strarray_appendm(&service_argv, argv[optind++]);
359 
360             break;
361         }
362     }
363     /* grab the remaining arguments */
364     for (; optind < argc; optind++)
365         strarray_appendm(&service_argv, argv[optind]);
366 
367     opterr = 1; /* enable error reporting */
368     optind = 1; /* reset the option index for parsing by the service */
369 
370     p = getenv("CYRUS_VERBOSE");
371     if (p) verbose = atoi(p) + 1;
372 
373     if (verbose > 30) {
374         syslog(LOG_DEBUG, "waiting 15 seconds for debugger");
375         sleep(15);
376     }
377 
378     p = getenv("CYRUS_SERVICE");
379     if (p == NULL) {
380         syslog(LOG_ERR, "could not getenv(CYRUS_SERVICE); exiting");
381         exit(EX_SOFTWARE);
382     }
383     service = xstrdup(p);
384 
385     p = getenv("CYRUS_ID");
386     if (p == NULL) {
387         syslog(LOG_ERR, "could not getenv(CYRUS_ID); exiting");
388         exit(EX_SOFTWARE);
389     }
390     id = atoi(p);
391 
392     srand(time(NULL) * getpid());
393 
394     /* if timeout is enabled, pick a random timeout between reuse_timeout
395      * and 2*reuse_timeout to avoid massive IO overload if the network
396      * connection goes away */
397     if (reuse_timeout)
398         reuse_timeout = reuse_timeout + (rand() % reuse_timeout);
399 
400     extern const int config_need_data;
401     cyrus_init(alt_config, service, 0, config_need_data);
402 
403     if (call_debugger) {
404         char debugbuf[1024];
405         int ret;
406         const char *debugger = config_getstring(IMAPOPT_DEBUG_COMMAND);
407         if (debugger) {
408 #pragma GCC diagnostic push
409 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
410 #pragma GCC diagnostic ignored "-Wformat-security"
411             /* This is exactly the kind of usage that -Wformat is designed to
412              * complain about (using user-supplied string as format argument),
413              * but in this case the "user" is the server administrator, and
414              * they're about to attach a debugger, so worrying about leaking
415              * contents of memory here is a little silly! :)
416              */
417             snprintf(debugbuf, sizeof(debugbuf), debugger,
418                      argv[0], getpid(), service);
419 #pragma GCC diagnostic pop
420             syslog(LOG_DEBUG, "running external debugger: %s", debugbuf);
421             ret = system(debugbuf); /* run debugger */
422             syslog(LOG_DEBUG, "debugger returned exit status: %d", ret);
423         }
424     }
425     syslog(LOG_DEBUG, "executed");
426 
427     if (debug_stdio) {
428         if (service_init(service_argv.count, service_argv.data, envp) != 0) {
429             return 1;
430         }
431     }
432     else {
433         /* set close on exec */
434         fdflags = fcntl(LISTEN_FD, F_GETFD, 0);
435         if (fdflags != -1) fdflags = fcntl(LISTEN_FD, F_SETFD,
436                                         fdflags | FD_CLOEXEC);
437         if (fdflags == -1) {
438             syslog(LOG_ERR, "unable to set close on exec: %m");
439             if (MESSAGE_MASTER_ON_EXIT)
440                 notify_master(STATUS_FD, MASTER_SERVICE_UNAVAILABLE);
441             return 1;
442         }
443         fdflags = fcntl(STATUS_FD, F_GETFD, 0);
444         if (fdflags != -1) fdflags = fcntl(STATUS_FD, F_SETFD,
445                                         fdflags | FD_CLOEXEC);
446         if (fdflags == -1) {
447             syslog(LOG_ERR, "unable to set close on exec: %m");
448             if (MESSAGE_MASTER_ON_EXIT)
449                 notify_master(STATUS_FD, MASTER_SERVICE_UNAVAILABLE);
450             return 1;
451         }
452 
453         /* figure out what sort of socket this is */
454         if (getsockopt(LISTEN_FD, SOL_SOCKET, SO_TYPE,
455                     (char *) &soctype, &typelen) < 0) {
456             syslog(LOG_ERR, "getsockopt: SOL_SOCKET: failed to get type: %m");
457             if (MESSAGE_MASTER_ON_EXIT)
458                 notify_master(STATUS_FD, MASTER_SERVICE_UNAVAILABLE);
459             return 1;
460         }
461         if (getsockname(LISTEN_FD, &socname, &addrlen) < 0) {
462             syslog(LOG_ERR, "getsockname: failed: %m");
463             if (MESSAGE_MASTER_ON_EXIT)
464                 notify_master(STATUS_FD, MASTER_SERVICE_UNAVAILABLE);
465             return 1;
466         }
467 
468         if (service_init(service_argv.count, service_argv.data, envp) != 0) {
469             if (MESSAGE_MASTER_ON_EXIT)
470                 notify_master(STATUS_FD, MASTER_SERVICE_UNAVAILABLE);
471             return 1;
472         }
473     }
474 
475     /* determine initial process file inode, size and mtime */
476     if (service_argv.data[0][0] == '/')
477         strlcpy(path, service_argv.data[0], sizeof(path));
478     else
479         snprintf(path, sizeof(path), "%s/%s", LIBEXEC_DIR, service_argv.data[0]);
480 
481     stat(path, &sbuf);
482     start_ino= sbuf.st_ino;
483     start_size = sbuf.st_size;
484     start_mtime = sbuf.st_mtime;
485 
486     getlockfd(service, id);
487 
488     if (debug_stdio) {
489         service_main(service_argv.count, service_argv.data, envp);
490         service_abort(0);
491         return 0;
492     }
493 
494     for (;;) {
495         /* ok, listen to this socket until someone talks to us */
496 
497         /* (re)set signal handlers, including SIGALRM */
498         signals_add_handlers(SIGALRM);
499 
500         if (use_count > 0) {
501             /* we want to time out after 60 seconds, set an alarm */
502             alarm(reuse_timeout);
503         }
504 
505         /* lock */
506         lockaccept();
507 
508         fd = -1;
509         while (fd < 0 && !signals_poll()) { /* loop until we succeed */
510             /* check current process file inode, size and mtime */
511             int r = stat(path, &sbuf);
512             if (r < 0) {
513                 /* This might happen transiently during a package
514                  * upgrade or permanently after package removal.
515                  * In either case, it's time to die. */
516                 syslog(LOG_INFO, "cannot stat process file: %m");
517                 break;
518             }
519             if (sbuf.st_ino != start_ino || sbuf.st_size != start_size ||
520                 sbuf.st_mtime != start_mtime) {
521                 syslog(LOG_INFO, "process file has changed");
522                 newfile = 1;
523                 break;
524             }
525 
526             if (soctype == SOCK_STREAM) {
527                 /* Wait for the file descriptor to be connected to, in a
528                  * signal-safe manner.  This ensures the accept() does
529                  * not block and we don't need to make it signal-safe.  */
530                 if (safe_wait_readable(LISTEN_FD) < 0)
531                     continue;
532                 fd = accept(LISTEN_FD, NULL, NULL);
533                 if (fd < 0) {
534                     switch (errno) {
535                     case EINTR:
536                         signals_poll();
537                     case ENETDOWN:
538 #ifdef EPROTO
539                     case EPROTO:
540 #endif
541                     case ENOPROTOOPT:
542                     case EHOSTDOWN:
543 #ifdef ENONET
544                     case ENONET:
545 #endif
546                     case EHOSTUNREACH:
547                     case EOPNOTSUPP:
548                     case ENETUNREACH:
549                     case ECONNABORTED:
550                     case EAGAIN:
551                         break;
552 
553                     case EINVAL:
554                         if (signals_poll() == SIGHUP) break;
555                         GCC_FALLTHROUGH
556 
557                     default:
558                         syslog(LOG_ERR, "accept failed: %m");
559                         if (MESSAGE_MASTER_ON_EXIT)
560                             notify_master(STATUS_FD, MASTER_SERVICE_UNAVAILABLE);
561                         service_abort(EX_OSERR);
562                     }
563                 }
564             } else {
565                 /* udp */
566                 struct sockaddr_storage from;
567                 socklen_t fromlen;
568                 char ch;
569                 int r;
570 
571                 if (safe_wait_readable(LISTEN_FD) < 0)
572                     continue;
573                 fromlen = sizeof(from);
574                 r = recvfrom(LISTEN_FD, (void *) &ch, 1, MSG_PEEK,
575                              (struct sockaddr *) &from, &fromlen);
576                 if (r == -1) {
577                     if (signals_poll() == SIGHUP) break;
578                     syslog(LOG_ERR, "recvfrom failed: %m");
579                     if (MESSAGE_MASTER_ON_EXIT)
580                         notify_master(STATUS_FD, MASTER_SERVICE_UNAVAILABLE);
581                     service_abort(EX_OSERR);
582                 }
583                 fd = LISTEN_FD;
584             }
585         }
586 
587         /* unlock */
588         unlockaccept();
589 
590         if (fd < 0 && (signals_poll() || newfile)) {
591             /* timed out (SIGALRM), SIGHUP, or new process file */
592             if (MESSAGE_MASTER_ON_EXIT)
593                 notify_master(STATUS_FD, MASTER_SERVICE_UNAVAILABLE);
594             service_abort(0);
595         }
596         if (fd < 0) {
597             /* how did this happen? - we might have caught a signal. */
598             syslog(LOG_ERR, "accept() failed but we didn't catch it?");
599             if (MESSAGE_MASTER_ON_EXIT)
600                 notify_master(STATUS_FD, MASTER_SERVICE_UNAVAILABLE);
601             service_abort(EX_SOFTWARE);
602         }
603 
604         /* cancel the alarm */
605         alarm(0);
606 
607         /* tcp only */
608         if(soctype == SOCK_STREAM && socname.sa_family != AF_UNIX) {
609             libwrap_init(&request, service);
610 
611             if (!libwrap_ask(&request, fd)) {
612                 /* connection denied! */
613                 shutdown(fd, SHUT_RDWR);
614                 close(fd);
615                 continue;
616             }
617 
618             tcp_enable_keepalive(fd);
619         }
620 
621         notify_master(STATUS_FD, MASTER_SERVICE_UNAVAILABLE);
622         syslog(LOG_DEBUG, "accepted connection");
623 
624         if (fd != STDIN_FILENO && dup2(fd, STDIN_FILENO) < 0) {
625             syslog(LOG_ERR, "can't duplicate accepted socket: %m");
626             service_abort(EX_OSERR);
627         }
628         if (fd != STDOUT_FILENO && dup2(fd, STDOUT_FILENO) < 0) {
629             syslog(LOG_ERR, "can't duplicate accepted socket: %m");
630             service_abort(EX_OSERR);
631         }
632 #if 0  /* XXX  This appears to have no valid use (and breaks wire protocols).
633           We should look into capturing stderr and sending it to syslog. */
634         if (fd != STDERR_FILENO && dup2(fd, STDERR_FILENO) < 0) {
635             syslog(LOG_ERR, "can't duplicate accepted socket: %m");
636             service_abort(EX_OSERR);
637         }
638 #endif
639 
640         /* tcp only */
641         if(soctype == SOCK_STREAM) {
642             if (fd > STDERR_FILENO) close(fd);
643         }
644 
645         notify_master(STATUS_FD, MASTER_SERVICE_CONNECTION);
646         use_count++;
647         service_main(service_argv.count, service_argv.data, envp);
648         /* if we returned, we can service another client with this process */
649 
650         if (signals_poll() || use_count >= max_use) {
651             /* caught SIGHUP or exceeded max use count */
652             break;
653         }
654 
655         notify_master(STATUS_FD, MASTER_SERVICE_AVAILABLE);
656     }
657 
658     service_abort(0);
659     return 0;
660 }
661