d896a6edadb607365e0f2d1fedcf92a59e8fd084
[openafs.git] / src / bozo / bosserver.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12 #include <afs/stds.h>
13
14 #include <afs/procmgmt.h>
15 #include <roken.h>
16
17 #ifdef IGNORE_SOME_GCC_WARNINGS
18 # pragma GCC diagnostic warning "-Wdeprecated-declarations"
19 #endif
20
21 #ifdef HAVE_SYS_RESOURCE_H
22 #include <sys/resource.h>
23 #endif
24
25 #ifdef AFS_NT40_ENV
26 #include <direct.h>
27 #include <WINNT/afsevent.h>
28 #endif /* AFS_NT40_ENV */
29
30 #include <rx/rx.h>
31 #include <rx/xdr.h>
32 #include <rx/rx_globals.h>
33 #include <rx/rxkad.h>
34 #include <rx/rxstat.h>
35 #include <afs/keys.h>
36 #include <afs/ktime.h>
37 #include <afs/afsutil.h>
38 #include <afs/fileutil.h>
39 #include <afs/audit.h>
40 #include <afs/cellconfig.h>
41
42 #if defined(AFS_SGI_ENV)
43 #include <afs/afs_args.h>
44 #endif
45
46 #include "bosint.h"
47 #include "bnode.h"
48 #include "bosprototypes.h"
49
50 #define BOZO_LWP_STACKSIZE      16000
51 extern struct bnode_ops fsbnode_ops, dafsbnode_ops, ezbnode_ops, cronbnode_ops;
52
53 struct afsconf_dir *bozo_confdir = 0;   /* bozo configuration dir */
54 static PROCESS bozo_pid;
55 const char *bozo_fileName;
56 FILE *bozo_logFile;
57
58 const char *DoCore;
59 int DoLogging = 0;
60 int DoSyslog = 0;
61 #ifndef AFS_NT40_ENV
62 int DoSyslogFacility = LOG_DAEMON;
63 #endif
64 static afs_int32 nextRestart;
65 static afs_int32 nextDay;
66
67 struct ktime bozo_nextRestartKT, bozo_nextDayKT;
68 int bozo_newKTs;
69 int rxBind = 0;
70 int rxkadDisableDotCheck = 0;
71
72 #define ADDRSPERSITE 16         /* Same global is in rx/rx_user.c */
73 afs_uint32 SHostAddrs[ADDRSPERSITE];
74
75 int bozo_isrestricted = 0;
76 int bozo_restdisable = 0;
77
78 void
79 bozo_insecureme(int sig)
80 {
81     signal(SIGFPE, bozo_insecureme);
82     bozo_isrestricted = 0;
83     bozo_restdisable = 1;
84 }
85
86 struct bztemp {
87     FILE *file;
88 };
89
90 /* check whether caller is authorized to manage RX statistics */
91 int
92 bozo_rxstat_userok(struct rx_call *call)
93 {
94     return afsconf_SuperUser(bozo_confdir, call, NULL);
95 }
96
97 /* restart bozo process */
98 int
99 bozo_ReBozo(void)
100 {
101 #ifdef AFS_NT40_ENV
102     /* exit with restart code; SCM integrator process will restart bosserver */
103     int status = BOSEXIT_RESTART;
104
105     /* if noauth flag is set, pass "-noauth" to new bosserver */
106     if (afsconf_GetNoAuthFlag(bozo_confdir)) {
107         status |= BOSEXIT_NOAUTH_FLAG;
108     }
109     /* if logging is on, pass "-log" to new bosserver */
110     if (DoLogging) {
111         status |= BOSEXIT_LOGGING_FLAG;
112     }
113     exit(status);
114 #else
115     /* exec new bosserver process */
116     char *argv[4];
117     int i = 0;
118
119     argv[i] = (char *)AFSDIR_SERVER_BOSVR_FILEPATH;
120     i++;
121
122     /* if noauth flag is set, pass "-noauth" to new bosserver */
123     if (afsconf_GetNoAuthFlag(bozo_confdir)) {
124         argv[i] = "-noauth";
125         i++;
126     }
127     /* if logging is on, pass "-log" to new bosserver */
128     if (DoLogging) {
129         argv[i] = "-log";
130         i++;
131     }
132 #ifndef AFS_NT40_ENV
133     /* if syslog logging is on, pass "-syslog" to new bosserver */
134     if (DoSyslog) {
135         char *arg = (char *)malloc(40); /* enough for -syslog=# */
136         if (DoSyslogFacility != LOG_DAEMON) {
137             snprintf(arg, 40, "-syslog=%d", DoSyslogFacility);
138         } else {
139             strcpy(arg, "-syslog");
140         }
141         argv[i] = arg;
142         i++;
143     }
144 #endif
145
146     /* null-terminate argument list */
147     argv[i] = NULL;
148
149     /* close random fd's */
150     for (i = 3; i < 64; i++) {
151         close(i);
152     }
153
154     execv(argv[0], argv);       /* should not return */
155     _exit(1);
156 #endif /* AFS_NT40_ENV */
157 }
158
159 /* make sure a dir exists */
160 static int
161 MakeDir(const char *adir)
162 {
163     struct stat tstat;
164     afs_int32 code;
165     if (stat(adir, &tstat) < 0 || (tstat.st_mode & S_IFMT) != S_IFDIR) {
166         int reqPerm;
167         unlink(adir);
168         reqPerm = GetRequiredDirPerm(adir);
169         if (reqPerm == -1)
170             reqPerm = 0777;
171 #ifdef AFS_NT40_ENV
172         /* underlying filesystem may not support directory protection */
173         code = mkdir(adir);
174 #else
175         code = mkdir(adir, reqPerm);
176 #endif
177         return code;
178     }
179     return 0;
180 }
181
182 /* create all the bozo dirs */
183 static int
184 CreateDirs(const char *coredir)
185 {
186     if ((!strncmp
187          (AFSDIR_USR_DIRPATH, AFSDIR_CLIENT_ETC_DIRPATH,
188           strlen(AFSDIR_USR_DIRPATH)))
189         ||
190         (!strncmp
191          (AFSDIR_USR_DIRPATH, AFSDIR_SERVER_BIN_DIRPATH,
192           strlen(AFSDIR_USR_DIRPATH)))) {
193         MakeDir(AFSDIR_USR_DIRPATH);
194     }
195     if (!strncmp
196         (AFSDIR_SERVER_AFS_DIRPATH, AFSDIR_SERVER_BIN_DIRPATH,
197          strlen(AFSDIR_SERVER_AFS_DIRPATH))) {
198         MakeDir(AFSDIR_SERVER_AFS_DIRPATH);
199     }
200     MakeDir(AFSDIR_SERVER_BIN_DIRPATH);
201     MakeDir(AFSDIR_SERVER_ETC_DIRPATH);
202     MakeDir(AFSDIR_SERVER_LOCAL_DIRPATH);
203     MakeDir(AFSDIR_SERVER_DB_DIRPATH);
204     MakeDir(AFSDIR_SERVER_LOGS_DIRPATH);
205 #ifndef AFS_NT40_ENV
206     if (!strncmp
207         (AFSDIR_CLIENT_VICE_DIRPATH, AFSDIR_CLIENT_ETC_DIRPATH,
208          strlen(AFSDIR_CLIENT_VICE_DIRPATH))) {
209         MakeDir(AFSDIR_CLIENT_VICE_DIRPATH);
210     }
211     MakeDir(AFSDIR_CLIENT_ETC_DIRPATH);
212
213     symlink(AFSDIR_SERVER_THISCELL_FILEPATH, AFSDIR_CLIENT_THISCELL_FILEPATH);
214     symlink(AFSDIR_SERVER_CELLSERVDB_FILEPATH,
215             AFSDIR_CLIENT_CELLSERVDB_FILEPATH);
216 #endif /* AFS_NT40_ENV */
217     if (coredir)
218         MakeDir(coredir);
219     return 0;
220 }
221
222 /* strip the \\n from the end of the line, if it is present */
223 static int
224 StripLine(char *abuffer)
225 {
226     char *tp;
227
228     tp = abuffer + strlen(abuffer);     /* starts off pointing at the null  */
229     if (tp == abuffer)
230         return 0;               /* null string, no last character to check */
231     tp--;                       /* aim at last character */
232     if (*tp == '\n')
233         *tp = 0;
234     return 0;
235 }
236
237 /* write one bnode's worth of entry into the file */
238 static int
239 bzwrite(struct bnode *abnode, void *arock)
240 {
241     struct bztemp *at = (struct bztemp *)arock;
242     int i;
243     char tbuffer[BOZO_BSSIZE];
244     afs_int32 code;
245
246     if (abnode->notifier)
247         fprintf(at->file, "bnode %s %s %d %s\n", abnode->type->name,
248                 abnode->name, abnode->fileGoal, abnode->notifier);
249     else
250         fprintf(at->file, "bnode %s %s %d\n", abnode->type->name,
251                 abnode->name, abnode->fileGoal);
252     for (i = 0;; i++) {
253         code = bnode_GetParm(abnode, i, tbuffer, BOZO_BSSIZE);
254         if (code) {
255             if (code != BZDOM)
256                 return code;
257             break;
258         }
259         fprintf(at->file, "parm %s\n", tbuffer);
260     }
261     fprintf(at->file, "end\n");
262     return 0;
263 }
264
265 #define MAXPARMS    20
266 int
267 ReadBozoFile(char *aname)
268 {
269     FILE *tfile;
270     char tbuffer[BOZO_BSSIZE];
271     char *tp;
272     char *instp, *typep, *notifier, *notp;
273     afs_int32 code;
274     afs_int32 ktmask, ktday, kthour, ktmin, ktsec;
275     afs_int32 i, goal;
276     struct bnode *tb;
277     char *parms[MAXPARMS];
278     char *thisparms[MAXPARMS];
279     int rmode;
280
281     /* rename BozoInit to BosServer for the user */
282     if (!aname) {
283         /* if BozoInit exists and BosConfig doesn't, try a rename */
284         if (access(AFSDIR_SERVER_BOZINIT_FILEPATH, 0) == 0
285             && access(AFSDIR_SERVER_BOZCONF_FILEPATH, 0) != 0) {
286             code =
287                 renamefile(AFSDIR_SERVER_BOZINIT_FILEPATH,
288                            AFSDIR_SERVER_BOZCONF_FILEPATH);
289             if (code < 0)
290                 perror("bosconfig rename");
291         }
292         if (access(AFSDIR_SERVER_BOZCONFNEW_FILEPATH, 0) == 0) {
293             code =
294                 renamefile(AFSDIR_SERVER_BOZCONFNEW_FILEPATH,
295                            AFSDIR_SERVER_BOZCONF_FILEPATH);
296             if (code < 0)
297                 perror("bosconfig rename");
298         }
299     }
300
301     /* don't do server restarts by default */
302     bozo_nextRestartKT.mask = KTIME_NEVER;
303     bozo_nextRestartKT.hour = 0;
304     bozo_nextRestartKT.min = 0;
305     bozo_nextRestartKT.day = 0;
306
307     /* restart processes at 5am if their binaries have changed */
308     bozo_nextDayKT.mask = KTIME_HOUR | KTIME_MIN;
309     bozo_nextDayKT.hour = 5;
310     bozo_nextDayKT.min = 0;
311
312     for (code = 0; code < MAXPARMS; code++)
313         parms[code] = NULL;
314     tfile = (FILE *) 0;
315     if (!aname)
316         aname = (char *)bozo_fileName;
317     tfile = fopen(aname, "r");
318     if (!tfile)
319         return 0;               /* -1 */
320     instp = malloc(BOZO_BSSIZE);
321     typep = malloc(BOZO_BSSIZE);
322     notifier = notp = malloc(BOZO_BSSIZE);
323     while (1) {
324         /* ok, read lines giving parms and such from the file */
325         tp = fgets(tbuffer, sizeof(tbuffer), tfile);
326         if (tp == (char *)0)
327             break;              /* all done */
328
329         if (strncmp(tbuffer, "restarttime", 11) == 0) {
330             code =
331                 sscanf(tbuffer, "restarttime %d %d %d %d %d", &ktmask, &ktday,
332                        &kthour, &ktmin, &ktsec);
333             if (code != 5) {
334                 code = -1;
335                 goto fail;
336             }
337             /* otherwise we've read in the proper ktime structure; now assign
338              * it and continue processing */
339             bozo_nextRestartKT.mask = ktmask;
340             bozo_nextRestartKT.day = ktday;
341             bozo_nextRestartKT.hour = kthour;
342             bozo_nextRestartKT.min = ktmin;
343             bozo_nextRestartKT.sec = ktsec;
344             continue;
345         }
346
347         if (strncmp(tbuffer, "checkbintime", 12) == 0) {
348             code =
349                 sscanf(tbuffer, "checkbintime %d %d %d %d %d", &ktmask,
350                        &ktday, &kthour, &ktmin, &ktsec);
351             if (code != 5) {
352                 code = -1;
353                 goto fail;
354             }
355             /* otherwise we've read in the proper ktime structure; now assign
356              * it and continue processing */
357             bozo_nextDayKT.mask = ktmask;       /* time to restart the system */
358             bozo_nextDayKT.day = ktday;
359             bozo_nextDayKT.hour = kthour;
360             bozo_nextDayKT.min = ktmin;
361             bozo_nextDayKT.sec = ktsec;
362             continue;
363         }
364
365         if (strncmp(tbuffer, "restrictmode", 12) == 0) {
366             code = sscanf(tbuffer, "restrictmode %d", &rmode);
367             if (code != 1) {
368                 code = -1;
369                 goto fail;
370             }
371             if (rmode != 0 && rmode != 1) {
372                 code = -1;
373                 goto fail;
374             }
375             bozo_isrestricted = rmode;
376             continue;
377         }
378
379         if (strncmp("bnode", tbuffer, 5) != 0) {
380             code = -1;
381             goto fail;
382         }
383         notifier = notp;
384         code =
385             sscanf(tbuffer, "bnode %s %s %d %s", typep, instp, &goal,
386                    notifier);
387         if (code < 3) {
388             code = -1;
389             goto fail;
390         } else if (code == 3)
391             notifier = NULL;
392
393         memset(thisparms, 0, sizeof(thisparms));
394
395         for (i = 0; i < MAXPARMS; i++) {
396             /* now read the parms, until we see an "end" line */
397             tp = fgets(tbuffer, sizeof(tbuffer), tfile);
398             if (!tp) {
399                 code = -1;
400                 goto fail;
401             }
402             StripLine(tbuffer);
403             if (!strncmp(tbuffer, "end", 3))
404                 break;
405             if (strncmp(tbuffer, "parm ", 5)) {
406                 code = -1;
407                 goto fail;      /* no "parm " either */
408             }
409             if (!parms[i])      /* make sure there's space */
410                 parms[i] = (char *)malloc(BOZO_BSSIZE);
411             strcpy(parms[i], tbuffer + 5);      /* remember the parameter for later */
412             thisparms[i] = parms[i];
413         }
414
415         /* ok, we have the type and parms, now create the object */
416         code =
417             bnode_Create(typep, instp, &tb, thisparms[0], thisparms[1],
418                          thisparms[2], thisparms[3], thisparms[4], notifier,
419                          goal ? BSTAT_NORMAL : BSTAT_SHUTDOWN, 0);
420         if (code)
421             goto fail;
422
423         /* bnode created in 'temporarily shutdown' state;
424          * check to see if we are supposed to run this guy,
425          * and if so, start the process up */
426         if (goal) {
427             bnode_SetStat(tb, BSTAT_NORMAL);    /* set goal, taking effect immediately */
428         } else {
429             bnode_SetStat(tb, BSTAT_SHUTDOWN);
430         }
431     }
432     /* all done */
433     code = 0;
434
435   fail:
436     if (instp)
437         free(instp);
438     if (typep)
439         free(typep);
440     for (i = 0; i < MAXPARMS; i++)
441         if (parms[i])
442             free(parms[i]);
443     if (tfile)
444         fclose(tfile);
445     return code;
446 }
447
448 /* write a new bozo file */
449 int
450 WriteBozoFile(char *aname)
451 {
452     FILE *tfile;
453     char tbuffer[AFSDIR_PATH_MAX];
454     afs_int32 code;
455     struct bztemp btemp;
456
457     if (!aname)
458         aname = (char *)bozo_fileName;
459     strcpy(tbuffer, aname);
460     strcat(tbuffer, ".NBZ");
461     tfile = fopen(tbuffer, "w");
462     if (!tfile)
463         return -1;
464     btemp.file = tfile;
465
466     fprintf(tfile, "restrictmode %d\n", bozo_isrestricted);
467     fprintf(tfile, "restarttime %d %d %d %d %d\n", bozo_nextRestartKT.mask,
468             bozo_nextRestartKT.day, bozo_nextRestartKT.hour,
469             bozo_nextRestartKT.min, bozo_nextRestartKT.sec);
470     fprintf(tfile, "checkbintime %d %d %d %d %d\n", bozo_nextDayKT.mask,
471             bozo_nextDayKT.day, bozo_nextDayKT.hour, bozo_nextDayKT.min,
472             bozo_nextDayKT.sec);
473     code = bnode_ApplyInstance(bzwrite, &btemp);
474     if (code || (code = ferror(tfile))) {       /* something went wrong */
475         fclose(tfile);
476         unlink(tbuffer);
477         return code;
478     }
479     /* close the file, check for errors and snap new file into place */
480     if (fclose(tfile) == EOF) {
481         unlink(tbuffer);
482         return -1;
483     }
484     code = renamefile(tbuffer, aname);
485     if (code) {
486         unlink(tbuffer);
487         return -1;
488     }
489     return 0;
490 }
491
492 static int
493 bdrestart(struct bnode *abnode, void *arock)
494 {
495     afs_int32 code;
496
497     if (abnode->fileGoal != BSTAT_NORMAL || abnode->goal != BSTAT_NORMAL)
498         return 0;               /* don't restart stopped bnodes */
499     bnode_Hold(abnode);
500     code = bnode_RestartP(abnode);
501     if (code) {
502         /* restart the dude */
503         bnode_SetStat(abnode, BSTAT_SHUTDOWN);
504         bnode_WaitStatus(abnode, BSTAT_SHUTDOWN);
505         bnode_SetStat(abnode, BSTAT_NORMAL);
506     }
507     bnode_Release(abnode);
508     return 0;                   /* keep trying all bnodes */
509 }
510
511 #define BOZO_MINSKIP 3600       /* minimum to advance clock */
512 /* lwp to handle system restarts */
513 static void *
514 BozoDaemon(void *unused)
515 {
516     afs_int32 now;
517
518     /* now initialize the values */
519     bozo_newKTs = 1;
520     while (1) {
521         IOMGR_Sleep(60);
522         now = FT_ApproxTime();
523
524         if (bozo_restdisable) {
525             bozo_Log("Restricted mode disabled by signal\n");
526             bozo_restdisable = 0;
527         }
528
529         if (bozo_newKTs) {      /* need to recompute restart times */
530             bozo_newKTs = 0;    /* done for a while */
531             nextRestart = ktime_next(&bozo_nextRestartKT, BOZO_MINSKIP);
532             nextDay = ktime_next(&bozo_nextDayKT, BOZO_MINSKIP);
533         }
534
535         /* see if we should do a restart */
536         if (now > nextRestart) {
537             SBOZO_ReBozo(0);    /* doesn't come back */
538         }
539
540         /* see if we should restart a server */
541         if (now > nextDay) {
542             nextDay = ktime_next(&bozo_nextDayKT, BOZO_MINSKIP);
543
544             /* call the bnode restartp function, and restart all that require it */
545             bnode_ApplyInstance(bdrestart, 0);
546         }
547     }
548     return NULL;
549 }
550
551 #ifdef AFS_AIX32_ENV
552 static int
553 tweak_config(void)
554 {
555     FILE *f;
556     char c[80];
557     int s, sb_max, ipfragttl;
558
559     sb_max = 131072;
560     ipfragttl = 20;
561     f = popen("/usr/sbin/no -o sb_max", "r");
562     s = fscanf(f, "sb_max = %d", &sb_max);
563     fclose(f);
564     if (s < 1)
565         return;
566     f = popen("/usr/sbin/no -o ipfragttl", "r");
567     s = fscanf(f, "ipfragttl = %d", &ipfragttl);
568     fclose(f);
569     if (s < 1)
570         ipfragttl = 20;
571
572     if (sb_max < 131072)
573         sb_max = 131072;
574     if (ipfragttl > 20)
575         ipfragttl = 20;
576
577     sprintf(c, "/usr/sbin/no -o sb_max=%d -o ipfragttl=%d", sb_max,
578             ipfragttl);
579     f = popen(c, "r");
580     fclose(f);
581 }
582 #endif
583
584 #if 0
585 /*
586  * This routine causes the calling process to go into the background and
587  * to lose its controlling tty.
588  *
589  * It does not close or otherwise alter the standard file descriptors.
590  *
591  * It writes warning messages to the standard error output if certain
592  * fundamental errors occur.
593  *
594  * This routine requires
595  *
596  * #include <sys/types.h>
597  * #include <sys/stat.h>
598  * #include <fcntl.h>
599  * #include <unistd.h>
600  * #include <stdlib.h>
601  *
602  * and has been tested on:
603  *
604  * AIX 4.2
605  * Digital Unix 4.0D
606  * HP-UX 11.0
607  * IRIX 6.5
608  * Linux 2.1.125
609  * Solaris 2.5
610  * Solaris 2.6
611  */
612
613 #ifndef AFS_NT40_ENV
614 static void
615 background(void)
616 {
617     /*
618      * A process is a process group leader if its process ID
619      * (getpid()) and its process group ID (getpgrp()) are the same.
620      */
621
622     /*
623      * To create a new session (and thereby lose our controlling
624      * terminal) we cannot be a process group leader.
625      *
626      * To guarantee we are not a process group leader, we fork and
627      * let the parent process exit.
628      */
629
630     if (getpid() == getpgrp()) {
631         pid_t pid;
632         pid = fork();
633         switch (pid) {
634         case -1:
635             abort();            /* leave footprints */
636             break;
637         case 0:         /* child */
638             break;
639         default:                /* parent */
640             exit(0);
641             break;
642         }
643     }
644
645     /*
646      * By here, we are not a process group leader, so we can make a
647      * new session and become the session leader.
648      */
649
650     {
651         pid_t sid = setsid();
652
653         if (sid == -1) {
654             static char err[] = "bosserver: WARNING: setsid() failed\n";
655             write(STDERR_FILENO, err, sizeof err - 1);
656         }
657     }
658
659     /*
660      * Once we create a new session, the current process is a
661      * session leader without a controlling tty.
662      *
663      * On some systems, the first tty device the session leader
664      * opens automatically becomes the controlling tty for the
665      * session.
666      *
667      * So, to guarantee we do not acquire a controlling tty, we fork
668      * and let the parent process exit.  The child process is not a
669      * session leader, and so it will not acquire a controlling tty
670      * even if it should happen to open a tty device.
671      */
672
673     if (getpid() == getpgrp()) {
674         pid_t pid;
675         pid = fork();
676         switch (pid) {
677         case -1:
678             abort();            /* leave footprints */
679             break;
680         case 0:         /* child */
681             break;
682         default:                /* parent */
683             exit(0);
684             break;
685         }
686     }
687
688     /*
689      * check that we no longer have a controlling tty
690      */
691
692     {
693         int fd;
694
695         fd = open("/dev/tty", O_RDONLY);
696
697         if (fd >= 0) {
698             static char err[] =
699                 "bosserver: WARNING: /dev/tty still attached\n";
700             close(fd);
701             write(STDERR_FILENO, err, sizeof err - 1);
702         }
703     }
704 }
705 #endif /* ! AFS_NT40_ENV */
706 #endif
707
708 /* start a process and monitor it */
709
710 #include "AFS_component_version_number.c"
711
712 int
713 main(int argc, char **argv, char **envp)
714 {
715     struct rx_service *tservice;
716     afs_int32 code;
717     struct afsconf_dir *tdir;
718     int noAuth = 0;
719     int i;
720     char namebuf[AFSDIR_PATH_MAX];
721     int rxMaxMTU = -1;
722     afs_uint32 host = htonl(INADDR_ANY);
723     char *auditFileName = NULL;
724     struct rx_securityClass **securityClasses;
725     afs_int32 numClasses;
726 #ifndef AFS_NT40_ENV
727     int nofork = 0;
728     struct stat sb;
729 #endif
730 #ifdef  AFS_AIX32_ENV
731     struct sigaction nsa;
732
733     /* for some reason, this permits user-mode RX to run a lot faster.
734      * we do it here in the bosserver, so we don't have to do it
735      * individually in each server.
736      */
737     tweak_config();
738
739     /*
740      * The following signal action for AIX is necessary so that in case of a
741      * crash (i.e. core is generated) we can include the user's data section
742      * in the core dump. Unfortunately, by default, only a partial core is
743      * generated which, in many cases, isn't too useful.
744      */
745     sigemptyset(&nsa.sa_mask);
746     nsa.sa_handler = SIG_DFL;
747     nsa.sa_flags = SA_FULLDUMP;
748     sigaction(SIGSEGV, &nsa, NULL);
749     sigaction(SIGABRT, &nsa, NULL);
750 #endif
751     osi_audit_init();
752     signal(SIGFPE, bozo_insecureme);
753
754 #ifdef AFS_NT40_ENV
755     /* Initialize winsock */
756     if (afs_winsockInit() < 0) {
757         ReportErrorEventAlt(AFSEVT_SVR_WINSOCK_INIT_FAILED, 0, argv[0], 0);
758         fprintf(stderr, "%s: Couldn't initialize winsock.\n", argv[0]);
759         exit(2);
760     }
761 #endif
762
763     /* Initialize dirpaths */
764     if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) {
765 #ifdef AFS_NT40_ENV
766         ReportErrorEventAlt(AFSEVT_SVR_NO_INSTALL_DIR, 0, argv[0], 0);
767 #endif
768         fprintf(stderr, "%s: Unable to obtain AFS server directory.\n",
769                 argv[0]);
770         exit(2);
771     }
772
773     /* some path inits */
774     bozo_fileName = AFSDIR_SERVER_BOZCONF_FILEPATH;
775     DoCore = AFSDIR_SERVER_LOGS_DIRPATH;
776
777     /* initialize the list of dirpaths that the bosserver has
778      * an interest in monitoring */
779     initBosEntryStats();
780
781 #if defined(AFS_SGI_ENV)
782     /* offer some protection if AFS isn't loaded */
783     if (syscall(AFS_SYSCALL, AFSOP_ENDLOG) < 0 && errno == ENOPKG) {
784         printf("bosserver: AFS doesn't appear to be configured in O.S..\n");
785         exit(1);
786     }
787 #endif
788
789     /* parse cmd line */
790     for (code = 1; code < argc; code++) {
791         if (strcmp(argv[code], "-noauth") == 0) {
792             /* set noauth flag */
793             noAuth = 1;
794         } else if (strcmp(argv[code], "-log") == 0) {
795             /* set extra logging flag */
796             DoLogging = 1;
797         }
798 #ifndef AFS_NT40_ENV
799         else if (strcmp(argv[code], "-syslog") == 0) {
800             /* set syslog logging flag */
801             DoSyslog = 1;
802         } else if (strncmp(argv[code], "-syslog=", 8) == 0) {
803             DoSyslog = 1;
804             DoSyslogFacility = atoi(argv[code] + 8);
805         } else if (strncmp(argv[code], "-cores=", 7) == 0) {
806             if (strcmp((argv[code]+7), "none") == 0)
807                 DoCore = 0;
808             else
809                 DoCore = (argv[code]+7);
810         } else if (strcmp(argv[code], "-nofork") == 0) {
811             nofork = 1;
812         }
813 #endif
814         else if (strcmp(argv[code], "-enable_peer_stats") == 0) {
815             rx_enablePeerRPCStats();
816         } else if (strcmp(argv[code], "-enable_process_stats") == 0) {
817             rx_enableProcessRPCStats();
818         }
819         else if (strcmp(argv[code], "-restricted") == 0) {
820             bozo_isrestricted = 1;
821         }
822         else if (strcmp(argv[code], "-rxbind") == 0) {
823             rxBind = 1;
824         }
825         else if (strcmp(argv[code], "-allow-dotted-principals") == 0) {
826             rxkadDisableDotCheck = 1;
827         }
828         else if (!strcmp(argv[code], "-rxmaxmtu")) {
829             if ((code + 1) >= argc) {
830                 fprintf(stderr, "missing argument for -rxmaxmtu\n");
831                 exit(1);
832             }
833             rxMaxMTU = atoi(argv[++code]);
834             if ((rxMaxMTU < RX_MIN_PACKET_SIZE) ||
835                 (rxMaxMTU > RX_MAX_PACKET_DATA_SIZE)) {
836                 printf("rxMaxMTU %d invalid; must be between %d-%" AFS_SIZET_FMT "\n",
837                         rxMaxMTU, RX_MIN_PACKET_SIZE,
838                         RX_MAX_PACKET_DATA_SIZE);
839                 exit(1);
840             }
841         }
842         else if (strcmp(argv[code], "-auditlog") == 0) {
843             auditFileName = argv[++code];
844
845         } else if (strcmp(argv[code], "-audit-interface") == 0) {
846             char *interface = argv[++code];
847
848             if (osi_audit_interface(interface)) {
849                 printf("Invalid audit interface '%s'\n", interface);
850                 exit(1);
851             }
852         }
853         else {
854
855             /* hack to support help flag */
856
857 #ifndef AFS_NT40_ENV
858             printf("Usage: bosserver [-noauth] [-log] "
859                    "[-auditlog <log path>] "
860                    "[-audit-interafce <file|sysvmq> (default is file)] "
861                    "[-rxmaxmtu <bytes>] [-rxbind] [-allow-dotted-principals]"
862                    "[-syslog[=FACILITY]] "
863                    "[-enable_peer_stats] [-enable_process_stats] "
864                    "[-cores=<none|path>] \n"
865                    "[-nofork] " "[-help]\n");
866 #else
867             printf("Usage: bosserver [-noauth] [-log] "
868                    "[-auditlog <log path>] "
869                    "[-audit-interafce <file|sysvmq> (default is file)] "
870                    "[-rxmaxmtu <bytes>] [-rxbind] [-allow-dotted-principals]"
871                    "[-enable_peer_stats] [-enable_process_stats] "
872                    "[-cores=<none|path>] \n"
873                    "[-help]\n");
874 #endif
875             fflush(stdout);
876
877             exit(0);
878         }
879     }
880     if (auditFileName) {
881         osi_audit_file(auditFileName);
882     }
883
884 #ifndef AFS_NT40_ENV
885     if (geteuid() != 0) {
886         printf("bosserver: must be run as root.\n");
887         exit(1);
888     }
889 #endif
890
891     code = bnode_Init();
892     if (code) {
893         printf("bosserver: could not init bnode package, code %d\n", code);
894         exit(1);
895     }
896
897     bnode_Register("fs", &fsbnode_ops, 3);
898     bnode_Register("dafs", &dafsbnode_ops, 4);
899     bnode_Register("simple", &ezbnode_ops, 1);
900     bnode_Register("cron", &cronbnode_ops, 2);
901
902     /* create useful dirs */
903     CreateDirs(DoCore);
904
905     /* chdir to AFS log directory */
906     if (DoCore)
907         chdir(DoCore);
908     else
909         chdir(AFSDIR_SERVER_LOGS_DIRPATH);
910
911 #if 0
912     fputs(AFS_GOVERNMENT_MESSAGE, stdout);
913     fflush(stdout);
914 #endif
915
916     /* go into the background and remove our controlling tty, close open
917        file desriptors
918      */
919
920 #ifndef AFS_NT40_ENV
921     if (!nofork)
922         daemon(1, 0);
923 #endif /* ! AFS_NT40_ENV */
924
925     if ((!DoSyslog)
926 #ifndef AFS_NT40_ENV
927         && ((lstat(AFSDIR_BOZLOG_FILE, &sb) == 0) &&
928         !(S_ISFIFO(sb.st_mode)))
929 #endif
930         ) {
931         strcpy(namebuf, AFSDIR_BOZLOG_FILE);
932         strcat(namebuf, ".old");
933         renamefile(AFSDIR_BOZLOG_FILE, namebuf);        /* try rename first */
934         bozo_logFile = fopen(AFSDIR_BOZLOG_FILE, "a");
935         if (!bozo_logFile) {
936             printf("bosserver: can't initialize log file (%s).\n",
937                    AFSDIR_SERVER_BOZLOG_FILEPATH);
938             exit(1);
939         }
940         /* keep log closed normally, so can be removed */
941         fclose(bozo_logFile);
942     } else {
943 #ifndef AFS_NT40_ENV
944         openlog("bosserver", LOG_PID, DoSyslogFacility);
945 #endif
946     }
947
948 #if defined(RLIMIT_CORE) && defined(HAVE_GETRLIMIT)
949     {
950       struct rlimit rlp;
951       getrlimit(RLIMIT_CORE, &rlp);
952       if (!DoCore)
953           rlp.rlim_cur = 0;
954       else
955           rlp.rlim_max = rlp.rlim_cur = RLIM_INFINITY;
956       setrlimit(RLIMIT_CORE, &rlp);
957       getrlimit(RLIMIT_CORE, &rlp);
958       bozo_Log("Core limits now %d %d\n",(int)rlp.rlim_cur,(int)rlp.rlim_max);
959     }
960 #endif
961
962     /* Write current state of directory permissions to log file */
963     DirAccessOK();
964
965     if (rxBind) {
966         afs_int32 ccode;
967         if (AFSDIR_SERVER_NETRESTRICT_FILEPATH ||
968             AFSDIR_SERVER_NETINFO_FILEPATH) {
969             char reason[1024];
970             ccode = parseNetFiles(SHostAddrs, NULL, NULL,
971                                   ADDRSPERSITE, reason,
972                                   AFSDIR_SERVER_NETINFO_FILEPATH,
973                                   AFSDIR_SERVER_NETRESTRICT_FILEPATH);
974         } else {
975             ccode = rx_getAllAddr(SHostAddrs, ADDRSPERSITE);
976         }
977         if (ccode == 1)
978             host = SHostAddrs[0];
979     }
980
981     for (i = 0; i < 10; i++) {
982         if (rxBind) {
983             code = rx_InitHost(host, htons(AFSCONF_NANNYPORT));
984         } else {
985             code = rx_Init(htons(AFSCONF_NANNYPORT));
986         }
987         if (code) {
988             bozo_Log("can't initialize rx: code=%d\n", code);
989             sleep(3);
990         } else
991             break;
992     }
993     if (i >= 10) {
994         bozo_Log("Bos giving up, can't initialize rx\n");
995         exit(code);
996     }
997
998     code = LWP_CreateProcess(BozoDaemon, BOZO_LWP_STACKSIZE, /* priority */ 1,
999                              /* param */ NULL , "bozo-the-clown",
1000                              &bozo_pid);
1001
1002     /* try to read the key from the config file */
1003     tdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
1004     if (!tdir) {
1005         /* try to create local cell config file */
1006         struct afsconf_cell tcell;
1007         strcpy(tcell.name, "localcell");
1008         tcell.numServers = 1;
1009         code = gethostname(tcell.hostName[0], MAXHOSTCHARS);
1010         if (code) {
1011             bozo_Log("failed to get hostname, code %d\n", errno);
1012             exit(1);
1013         }
1014         if (tcell.hostName[0][0] == 0) {
1015             bozo_Log("host name not set, can't start\n");
1016             bozo_Log("try the 'hostname' command\n");
1017             exit(1);
1018         }
1019         memset(tcell.hostAddr, 0, sizeof(tcell.hostAddr));      /* not computed */
1020         code =
1021             afsconf_SetCellInfo(bozo_confdir, AFSDIR_SERVER_ETC_DIRPATH,
1022                                 &tcell);
1023         if (code) {
1024             bozo_Log
1025                 ("could not create cell database in '%s' (code %d), quitting\n",
1026                  AFSDIR_SERVER_ETC_DIRPATH, code);
1027             exit(1);
1028         }
1029         tdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
1030         if (!tdir) {
1031             bozo_Log
1032                 ("failed to open newly-created cell database, quitting\n");
1033             exit(1);
1034         }
1035     }
1036
1037     /* read init file, starting up programs */
1038     if ((code = ReadBozoFile(0))) {
1039         bozo_Log
1040             ("bosserver: Something is wrong (%d) with the bos configuration file %s; aborting\n",
1041              code, AFSDIR_SERVER_BOZCONF_FILEPATH);
1042         exit(code);
1043     }
1044
1045     /* opened the cell databse */
1046     bozo_confdir = tdir;
1047
1048     /* allow super users to manage RX statistics */
1049     rx_SetRxStatUserOk(bozo_rxstat_userok);
1050
1051     afsconf_SetNoAuthFlag(tdir, noAuth);
1052     afsconf_BuildServerSecurityObjects(tdir, &securityClasses, &numClasses);
1053
1054     /* Disable jumbograms */
1055     rx_SetNoJumbo();
1056
1057     if (rxMaxMTU != -1) {
1058         rx_SetMaxMTU(rxMaxMTU);
1059     }
1060
1061     tservice = rx_NewServiceHost(host, 0, /* service id */ 1,
1062                                  "bozo", securityClasses, numClasses,
1063                                  BOZO_ExecuteRequest);
1064     rx_SetMinProcs(tservice, 2);
1065     rx_SetMaxProcs(tservice, 4);
1066     rx_SetStackSize(tservice, BOZO_LWP_STACKSIZE);      /* so gethostbyname works (in cell stuff) */
1067     if (rxkadDisableDotCheck) {
1068         rx_SetSecurityConfiguration(tservice, RXS_CONFIG_FLAGS,
1069                                     (void *)RXS_CONFIG_FLAGS_DISABLE_DOTCHECK);
1070     }
1071
1072     tservice =
1073         rx_NewServiceHost(host, 0, RX_STATS_SERVICE_ID, "rpcstats",
1074                           securityClasses, numClasses, RXSTATS_ExecuteRequest);
1075     rx_SetMinProcs(tservice, 2);
1076     rx_SetMaxProcs(tservice, 4);
1077     rx_StartServer(1);          /* donate this process */
1078     return 0;
1079 }
1080
1081 void
1082 bozo_Log(char *format, ...)
1083 {
1084     char tdate[27];
1085     time_t myTime;
1086     va_list ap;
1087
1088     va_start(ap, format);
1089
1090     if (DoSyslog) {
1091 #ifndef AFS_NT40_ENV
1092         vsyslog(LOG_INFO, format, ap);
1093 #endif
1094     } else {
1095         myTime = time(0);
1096         strcpy(tdate, ctime(&myTime));  /* copy out of static area asap */
1097         tdate[24] = ':';
1098
1099         /* log normally closed, so can be removed */
1100
1101         bozo_logFile = fopen(AFSDIR_SERVER_BOZLOG_FILEPATH, "a");
1102         if (bozo_logFile == NULL) {
1103             printf("bosserver: WARNING: problem with %s\n",
1104                    AFSDIR_SERVER_BOZLOG_FILEPATH);
1105             printf("%s ", tdate);
1106             vprintf(format, ap);
1107             fflush(stdout);
1108         } else {
1109             fprintf(bozo_logFile, "%s ", tdate);
1110             vfprintf(bozo_logFile, format, ap);
1111
1112             /* close so rm BosLog works */
1113             fclose(bozo_logFile);
1114         }
1115     }
1116 }