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