]> andersk Git - moira.git/blob - server/mr_main.c
Use krb5 auth, not krb4.
[moira.git] / server / mr_main.c
1 /* $Id$
2  *
3  * Moira server process.
4  *
5  * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
6  * For copying and distribution information, please see the file
7  * <mit-copyright.h>.
8  *
9  */
10
11 #include <mit-copyright.h>
12 #include "mr_server.h"
13
14 #include <sys/socket.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
17 #include <sys/utsname.h>
18 #include <sys/wait.h>
19
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
22
23 #include <ctype.h>
24 #include <errno.h>
25 #include <signal.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30
31 #include <krb.h>
32 #include <krb5.h>
33
34 RCSID("$Header$");
35
36 client *cur_client;
37
38 char *whoami;
39 char *takedown;
40 FILE *journal;
41
42 time_t now;
43
44 char *host;
45 char krb_realm[REALM_SZ];
46 krb5_context context = NULL;
47
48 /* Client array and associated data. This needs to be global for _list_users */
49 client **clients;
50 int nclients, clientssize;
51
52 int dormant;
53
54 void reapchild(int x);
55 void godormant(int x);
56 void gowakeup(int x);
57 void clist_append(client *cp);
58 void mr_setup_signals(void);
59
60 /*
61  * Main Moira server loop.
62  *
63  * Initialize the world, then start accepting connections and
64  * making progress on current connections.
65  */
66
67 int main(int argc, char **argv)
68 {
69   int status, i, listener;
70   time_t tardy;
71   char *port, *p;
72   extern char *database;
73   struct stat stbuf;
74   struct utsname uts;
75   fd_set readfds, writefds, xreadfds, xwritefds;
76   int nfds, counter = 0;
77
78   whoami = argv[0];
79   /*
80    * Error handler init.
81    */
82   mr_init();
83   set_com_err_hook(mr_com_err);
84   setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
85
86   port = strchr(MOIRA_SERVER, ':') + 1;
87
88   for (i = 1; i < argc; i++)
89     {
90       if (!strcmp(argv[i], "-db") && i + 1 < argc)
91         {
92           database = argv[i + 1];
93           i++;
94         }
95       else if (!strcmp(argv[i], "-p") && i + 1 < argc)
96         {
97           port = argv[i + 1];
98           i++;
99         }
100       else
101         {
102           com_err(whoami, 0, "Usage: moirad [-db database][-p port]");
103           exit(1);
104         }
105     }
106
107   krb_get_lrealm(krb_realm, 1);
108
109   status = krb5_init_context(&context);
110   if (status)
111     {
112       com_err(whoami, status, "Initializing krb5 context.");
113       exit(1);
114     }
115   krb5_init_ets(context);
116
117   /*
118    * Database initialization.  Only init if database should be open.
119    */
120
121   if (stat(MOIRA_MOTD_FILE, &stbuf) != 0)
122     {
123       if ((status = mr_open_database()))
124         {
125           com_err(whoami, status, "trying to open database.");
126           exit(1);
127         }
128       sanity_check_database();
129     }
130   else
131     {
132       dormant = ASLEEP;
133       com_err(whoami, 0, "sleeping, not opening database");
134     }
135
136   sanity_check_queries();
137
138   /*
139    * Get moira server hostname for authentication
140    */
141   if (uname(&uts) < 0)
142     {
143       com_err(whoami, errno, "Unable to get local hostname");
144       exit(1);
145     }
146   host = canonicalize_hostname(xstrdup(uts.nodename));
147   for (p = host; *p && *p != '.'; p++)
148     {
149       if (isupper(*p))
150         *p = tolower(*p);
151     }
152   *p = '\0';
153
154   /*
155    * Set up client array handler.
156    */
157   nclients = 0;
158   clientssize = 10;
159   clients = xmalloc(clientssize * sizeof(client *));
160
161   mr_setup_signals();
162
163   journal = fopen(JOURNAL, "a");
164   if (!journal)
165     {
166       com_err(whoami, errno, "opening journal file");
167       exit(1);
168     }
169
170   /*
171    * Establish template connection.
172    */
173   listener = mr_listen(port);
174   if (listener == -1)
175     {
176       com_err(whoami, MR_ABORTED, "trying to create listening connection");
177       exit(1);
178     }
179   FD_ZERO(&xreadfds);
180   FD_ZERO(&xwritefds);
181   FD_SET(listener, &xreadfds);
182   nfds = listener + 1;
183
184   com_err(whoami, 0, "started (pid %d)", getpid());
185   com_err(whoami, 0, rcsid);
186   if (dormant != ASLEEP)
187     send_zgram("MOIRA", "server started");
188   else
189     send_zgram("MOIRA", "server started, but database closed");
190
191   /*
192    * Run until shut down.
193    */
194   while (!takedown)
195     {
196       int i;
197       struct timeval timeout = {60, 0}; /* 1 minute */
198
199       /* If we're supposed to go down and we can, do it */
200       if (((dormant == AWAKE) && (nclients == 0) &&
201            (stat(MOIRA_MOTD_FILE, &stbuf) == 0)) ||
202           (dormant == SLEEPY))
203         {
204           mr_close_database();
205           com_err(whoami, 0, "database closed");
206           mr_setup_signals();
207           send_zgram("MOIRA", "database closed");
208           dormant = ASLEEP;
209         }
210
211       /* Block until something happens. */
212       memcpy(&readfds, &xreadfds, sizeof(readfds));
213       memcpy(&writefds, &xwritefds, sizeof(writefds));
214       if (select(nfds, &readfds, &writefds, NULL, &timeout) == -1)
215         {
216           if (errno != EINTR)
217             com_err(whoami, errno, "in select");
218           if (!inc_running || now - inc_started > INC_TIMEOUT)
219             next_incremental();
220           continue;
221         }
222
223       if (takedown)
224         break;
225       time(&now);
226       if (!inc_running || now - inc_started > INC_TIMEOUT)
227         next_incremental();
228       tardy = now - 30 * 60;
229
230       /* If we're asleep and we should wake up, do it */
231       if ((dormant == ASLEEP) && (stat(MOIRA_MOTD_FILE, &stbuf) == -1) &&
232           (errno == ENOENT))
233         {
234           mr_open_database();
235           com_err(whoami, 0, "database open");
236           mr_setup_signals();
237           send_zgram("MOIRA", "database open again");
238           dormant = AWAKE;
239         }
240
241       /* Handle any new connections */
242       if (FD_ISSET(listener, &readfds))
243         {
244           int newconn, addrlen = sizeof(struct sockaddr_in);
245           struct sockaddr_in addr;
246           client *cp;
247
248           newconn = accept(listener, (struct sockaddr *)&addr, &addrlen);
249           if (newconn == -1)
250             com_err(whoami, errno, "accepting new connection");
251           else if (newconn > 0)
252             {
253               if (newconn + 1 > nfds)
254                 nfds = newconn + 1;
255               FD_SET(newconn, &xreadfds);
256
257               /* Add a new client to the array */
258               nclients++;
259               if (nclients > clientssize)
260                 {
261                   clientssize = 2 * clientssize;
262                   clients = xrealloc(clients, clientssize * sizeof(client *));
263                 }
264
265               clients[nclients - 1] = cp = xmalloc(sizeof(client));
266               memset(cp, 0, sizeof(client));
267               cp->con = newconn;
268               cp->id = counter++;
269               cp->last_time_used = now;
270               cp->haddr = addr;
271               cp->tuplessize = 1;
272               cp->tuples = xmalloc(sizeof(mr_params));
273               memset(cp->tuples, 0, sizeof(mr_params));
274               cp->state = CL_ACCEPTING;
275               cp->version = 2;
276
277               cur_client = cp;
278               com_err(whoami, 0,
279                       "New connection from %s port %d (now %d client%s)",
280                       inet_ntoa(cp->haddr.sin_addr),
281                       (int)ntohs(cp->haddr.sin_port),
282                       nclients, nclients != 1 ? "s" : "");
283             }
284         }
285
286       /* Handle any existing connections. */
287       for (i = 0; i < nclients; i++)
288         {
289           cur_client = clients[i];
290
291           if (FD_ISSET(clients[i]->con, &writefds))
292             {
293               client_write(clients[i]);
294               if (!clients[i]->ntuples)
295                 {
296                   FD_CLR(clients[i]->con, &xwritefds);
297                   FD_SET(clients[i]->con, &xreadfds);
298                 }
299               clients[i]->last_time_used = now;
300             }
301
302           if (FD_ISSET(clients[i]->con, &readfds))
303             {
304               if (clients[i]->state == CL_ACCEPTING)
305                 {
306                   switch(mr_cont_accept(clients[i]->con,
307                                         &clients[i]->hsbuf,
308                                         &clients[i]->hslen))
309                     {
310                     case -1:
311                       break;
312
313                     case 0:
314                       clients[i]->state = CL_CLOSING;
315                       break;
316
317                     default:
318                       clients[i]->state = CL_ACTIVE;
319                       clients[i]->hsbuf = NULL;
320                       break;
321                     }
322                 }
323               else
324                 {
325                   client_read(clients[i]);
326                   if (clients[i]->ntuples)
327                     {
328                       FD_CLR(clients[i]->con, &xreadfds);
329                       FD_SET(clients[i]->con, &xwritefds);
330                     }
331                   clients[i]->last_time_used = now;
332                 }
333             }
334
335           if (clients[i]->last_time_used < tardy)
336             {
337               com_err(whoami, 0, "Shutting down connection due to inactivity");
338               clients[i]->state = CL_CLOSING;
339             }
340
341           if (clients[i]->state == CL_CLOSING)
342             {
343               client *old;
344
345               com_err(whoami, 0, "Closed connection (now %d client%s, "
346                       "%d queries)", nclients - 1, nclients != 2 ? "s" : "",
347                       newqueries);
348
349               shutdown(clients[i]->con, 2);
350               close(clients[i]->con);
351               FD_CLR(clients[i]->con, &xreadfds);
352               FD_CLR(clients[i]->con, &xwritefds);
353               free_rtn_tuples(clients[i]);
354               free(clients[i]->tuples);
355               free(clients[i]->hsbuf);
356               old = clients[i];
357               clients[i] = clients[--nclients];
358               free(old);
359             }
360
361           cur_client = NULL;
362           if (takedown)
363             break;
364         }
365     }
366
367   com_err(whoami, 0, "%s", takedown);
368   if (dormant != ASLEEP)
369     mr_close_database();
370   send_zgram("MOIRA", takedown);
371   return 0;
372 }
373
374 void reapchild(int x)
375 {
376   int status, pid;
377
378   while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
379     {
380       if (pid == inc_pid)
381         inc_running = 0;
382       if (!takedown && (WTERMSIG(status) != 0 || WEXITSTATUS(status) != 0))
383         {
384           critical_alert("moirad", "%d: child exits with signal %d status %d",
385                          pid, WTERMSIG(status), WEXITSTATUS(status));
386         }
387     }
388 }
389
390
391 void godormant(int x)
392 {
393   switch (dormant)
394     {
395     case AWAKE:
396     case GROGGY:
397       com_err(whoami, 0, "requested to go dormant");
398       break;
399     case ASLEEP:
400       com_err(whoami, 0, "already asleep");
401       break;
402     case SLEEPY:
403       break;
404     }
405   dormant = SLEEPY;
406 }
407
408
409 void gowakeup(int x)
410 {
411   switch (dormant)
412     {
413     case ASLEEP:
414     case SLEEPY:
415       com_err(whoami, 0, "Good morning");
416       break;
417     case AWAKE:
418       com_err(whoami, 0, "already awake");
419       break;
420     case GROGGY:
421       break;
422     }
423   dormant = GROGGY;
424 }
425
426
427 void mr_setup_signals(void)
428 {
429   struct sigaction action;
430
431   action.sa_flags = 0;
432   sigemptyset(&action.sa_mask);
433
434   /* There should probably be a few more of these. */
435
436   action.sa_handler = sigshut;
437   if ((sigaction(SIGTERM, &action, NULL) < 0) ||
438       (sigaction(SIGINT, &action, NULL) < 0) ||
439       (sigaction(SIGHUP, &action, NULL) < 0))
440     {
441       com_err(whoami, errno, "Unable to establish signal handlers.");
442       exit(1);
443     }
444
445   action.sa_handler = godormant;
446   if (sigaction(SIGUSR1, &action, NULL) < 0)
447     {
448       com_err(whoami, errno, "Unable to establish signal handlers.");
449       exit(1);
450     }
451
452   action.sa_handler = gowakeup;
453   if (sigaction(SIGUSR2, &action, NULL) < 0)
454     {
455       com_err(whoami, errno, "Unable to establish signal handlers.");
456       exit(1);
457     }
458
459   action.sa_handler = SIG_IGN;
460   if (sigaction(SIGPIPE, &action, NULL) < 0)
461     {
462       com_err(whoami, errno, "Unable to establish signal handlers.");
463       exit(1);
464     }
465
466   action.sa_handler = reapchild;
467   sigaddset(&action.sa_mask, SIGCHLD);
468   if (sigaction(SIGCHLD, &action, NULL) < 0)
469     {
470       com_err(whoami, errno, "Unable to establish signal handlers.");
471       exit(1);
472     }
473 }
This page took 0.084324 seconds and 5 git commands to generate.