Merge commit 'ceod'
[mspang/pyceo.git] / src / dmaster.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <signal.h>
5 #include <string.h>
6 #include <syslog.h>
7 #include <libgen.h>
8 #include <getopt.h>
9 #include <errno.h>
10 #include <netdb.h>
11 #include <alloca.h>
12
13 #include "util.h"
14 #include "net.h"
15 #include "config.h"
16 #include "gss.h"
17 #include "daemon.h"
18 #include "ldap.h"
19 #include "kadm.h"
20 #include "krb5.h"
21 #include "ops.h"
22
23 static struct option opts[] = {
24     { "detach", 0, NULL, 'd' },
25     { NULL, 0, NULL, '\0' },
26 };
27
28 char *prog = NULL;
29
30 int terminate = 0;
31 int fatal_signal;
32
33 static int detach = 0;
34
35 static void usage() {
36     fprintf(stderr, "Usage: %s [--detach]\n", prog);
37     exit(2);
38 }
39
40 static void signal_handler(int sig) {
41     if (sig == SIGTERM || sig == SIGINT) {
42         const char *s = (sig == SIGTERM) ? "terminated" : "interrupt";
43         notice("shutting down (%s)", s);
44         terminate = 1;
45         fatal_signal = sig;
46         signal(sig, SIG_DFL);
47     } else if (sig == SIGSEGV) {
48         error("segmentation fault");
49         signal(sig, SIG_DFL);
50         raise(sig);
51     } else if (sig != SIGCHLD) {
52         fatal("unhandled signal %d", sig);
53     }
54 }
55
56 static void setup_signals(void) {
57     struct sigaction sa;
58     memset(&sa, 0, sizeof(sa));
59     sigemptyset(&sa.sa_mask);
60     sa.sa_handler = signal_handler;
61
62     sigaction(SIGINT,  &sa, NULL);
63     sigaction(SIGTERM, &sa, NULL);
64     sigaction(SIGSEGV, &sa, NULL);
65
66     signal(SIGPIPE, SIG_IGN);
67     signal(SIGCHLD, SIG_IGN);
68 }
69
70 static void setup_daemon(void) {
71     if (chdir("/"))
72         fatalpe("chdir('/')");
73     if (detach) {
74         pid_t pid = fork();
75         if (pid < 0)
76             fatalpe("fork");
77         if (pid)
78             exit(0);
79         if (setsid() < 0)
80             fatalpe("setsid");
81         close(STDIN_FILENO);
82         close(STDOUT_FILENO);
83         close(STDERR_FILENO);
84     }
85 }
86
87 static void setup_auth(void) {
88     if (setenv("KRB5CCNAME", "MEMORY:ceod", 1))
89         fatalpe("setenv");
90     server_acquire_creds("ceod");
91 }
92
93 static void accept_one_client(int server) {
94     struct sockaddr_in addr;
95     socklen_t addrlen = sizeof(addr);
96     memset(&addr, 0, addrlen);
97
98     int client = accept(server, (sa *)&addr, &addrlen);
99     if (client < 0) {
100         if (errno == EINTR)
101             return;
102         fatalpe("accept");
103     }
104
105     pid_t pid = fork();
106     if (!pid) {
107         close(server);
108         slave_main(client, (sa *)&addr);
109         exit(0);
110     }
111
112     close(client);
113 }
114
115 static int master_main(void) {
116     int sock;
117     struct sockaddr_in addr;
118
119     memset(&addr, 0, sizeof(addr));
120     addr.sin_family = AF_INET;
121     addr.sin_port = htons(9987);
122     addr.sin_addr.s_addr = INADDR_ANY;
123
124     sock = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP);
125     if (sock < 0)
126         fatalpe("socket");
127
128     if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)))
129         fatalpe("bind");
130
131     if (listen(sock, 128))
132         fatalpe("listen");
133
134     setup_daemon();
135     setup_fqdn();
136     setup_signals();
137     setup_auth();
138     setup_ops();
139
140     notice("now accepting connections");
141
142     while (!terminate)
143         accept_one_client(sock);
144
145     free_gss();
146     free_fqdn();
147     free_ops();
148
149     return 0;
150 }
151
152 int main(int argc, char *argv[]) {
153     int opt;
154     int ret;
155
156     prog = xstrdup(basename(argv[0]));
157     init_log(prog, LOG_PID, LOG_DAEMON);
158
159     configure();
160
161     while ((opt = getopt_long(argc, argv, "", opts, NULL)) != -1) {
162         switch (opt) {
163             case 'd':
164                 detach = 1;
165                 break;
166             case '?':
167                 usage();
168                 break;
169             default:
170                 fatal("error parsing arguments");
171         }
172     }
173
174     if (argc != optind)
175         usage();
176
177     ret = master_main();
178
179     free_config();
180     free(prog);
181
182     return ret;
183 }