bozo: report bosserver -rxbind address
[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 const char *DoPidFiles = NULL;
62 #ifndef AFS_NT40_ENV
63 int DoSyslogFacility = LOG_DAEMON;
64 #endif
65 static afs_int32 nextRestart;
66 static afs_int32 nextDay;
67
68 struct ktime bozo_nextRestartKT, bozo_nextDayKT;
69 int bozo_newKTs;
70 int rxBind = 0;
71 int rxkadDisableDotCheck = 0;
72
73 #define ADDRSPERSITE 16         /* Same global is in rx/rx_user.c */
74 afs_uint32 SHostAddrs[ADDRSPERSITE];
75
76 int bozo_isrestricted = 0;
77 int bozo_restdisable = 0;
78
79 void
80 bozo_insecureme(int sig)
81 {
82     signal(SIGFPE, bozo_insecureme);
83     bozo_isrestricted = 0;
84     bozo_restdisable = 1;
85 }
86
87 struct bztemp {
88     FILE *file;
89 };
90
91 /* check whether caller is authorized to manage RX statistics */
92 int
93 bozo_rxstat_userok(struct rx_call *call)
94 {
95     return afsconf_SuperUser(bozo_confdir, call, NULL);
96 }
97
98 /* restart bozo process */
99 int
100 bozo_ReBozo(void)
101 {
102 #ifdef AFS_NT40_ENV
103     /* exit with restart code; SCM integrator process will restart bosserver */
104     int status = BOSEXIT_RESTART;
105
106     /* if noauth flag is set, pass "-noauth" to new bosserver */
107     if (afsconf_GetNoAuthFlag(bozo_confdir)) {
108         status |= BOSEXIT_NOAUTH_FLAG;
109     }
110     /* if logging is on, pass "-log" to new bosserver */
111     if (DoLogging) {
112         status |= BOSEXIT_LOGGING_FLAG;
113     }
114     /* if rxbind is set, pass "-rxbind" to new bosserver */
115     if (rxBind) {
116         status |= BOSEXIT_RXBIND_FLAG;
117     }
118     exit(status);
119 #else
120     /* exec new bosserver process */
121     char *argv[4];
122     int i = 0;
123
124     argv[i] = (char *)AFSDIR_SERVER_BOSVR_FILEPATH;
125     i++;
126
127     /* if noauth flag is set, pass "-noauth" to new bosserver */
128     if (afsconf_GetNoAuthFlag(bozo_confdir)) {
129         argv[i] = "-noauth";
130         i++;
131     }
132     /* if logging is on, pass "-log" to new bosserver */
133     if (DoLogging) {
134         argv[i] = "-log";
135         i++;
136     }
137     /* if rxbind is set, pass "-rxbind" to new bosserver */
138     if (rxBind) {
139         argv[i] = "-rxbind";
140         i++;
141     }
142 #ifndef AFS_NT40_ENV
143     /* if syslog logging is on, pass "-syslog" to new bosserver */
144     if (DoSyslog) {
145         char *arg = (char *)malloc(40); /* enough for -syslog=# */
146         if (DoSyslogFacility != LOG_DAEMON) {
147             snprintf(arg, 40, "-syslog=%d", DoSyslogFacility);
148         } else {
149             strcpy(arg, "-syslog");
150         }
151         argv[i] = arg;
152         i++;
153     }
154 #endif
155
156     /* null-terminate argument list */
157     argv[i] = NULL;
158
159     /* close random fd's */
160     for (i = 3; i < 64; i++) {
161         close(i);
162     }
163
164     unlink(AFSDIR_SERVER_BOZRXBIND_FILEPATH);
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     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(char *abuffer)
237 {
238     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(struct bnode *abnode, void *arock)
252 {
253     struct bztemp *at = (struct bztemp *)arock;
254     int i;
255     char tbuffer[BOZO_BSSIZE];
256     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     FILE *tfile;
282     char tbuffer[BOZO_BSSIZE];
283     char *tp;
284     char *instp, *typep, *notifier, *notp;
285     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     char *thisparms[MAXPARMS];
291     int rmode;
292
293     /* rename BozoInit to BosServer for the user */
294     if (!aname) {
295         /* if BozoInit exists and BosConfig doesn't, try a rename */
296         if (access(AFSDIR_SERVER_BOZINIT_FILEPATH, 0) == 0
297             && access(AFSDIR_SERVER_BOZCONF_FILEPATH, 0) != 0) {
298             code =
299                 renamefile(AFSDIR_SERVER_BOZINIT_FILEPATH,
300                            AFSDIR_SERVER_BOZCONF_FILEPATH);
301             if (code < 0)
302                 perror("bosconfig rename");
303         }
304         if (access(AFSDIR_SERVER_BOZCONFNEW_FILEPATH, 0) == 0) {
305             code =
306                 renamefile(AFSDIR_SERVER_BOZCONFNEW_FILEPATH,
307                            AFSDIR_SERVER_BOZCONF_FILEPATH);
308             if (code < 0)
309                 perror("bosconfig rename");
310         }
311     }
312
313     /* don't do server restarts by default */
314     bozo_nextRestartKT.mask = KTIME_NEVER;
315     bozo_nextRestartKT.hour = 0;
316     bozo_nextRestartKT.min = 0;
317     bozo_nextRestartKT.day = 0;
318
319     /* restart processes at 5am if their binaries have changed */
320     bozo_nextDayKT.mask = KTIME_HOUR | KTIME_MIN;
321     bozo_nextDayKT.hour = 5;
322     bozo_nextDayKT.min = 0;
323
324     for (code = 0; code < MAXPARMS; code++)
325         parms[code] = 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 = malloc(BOZO_BSSIZE);
333     typep = malloc(BOZO_BSSIZE);
334     notifier = notp = 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         memset(thisparms, 0, sizeof(thisparms));
406
407         for (i = 0; i < MAXPARMS; i++) {
408             /* now read the parms, until we see an "end" line */
409             tp = fgets(tbuffer, sizeof(tbuffer), tfile);
410             if (!tp) {
411                 code = -1;
412                 goto fail;
413             }
414             StripLine(tbuffer);
415             if (!strncmp(tbuffer, "end", 3))
416                 break;
417             if (strncmp(tbuffer, "parm ", 5)) {
418                 code = -1;
419                 goto fail;      /* no "parm " either */
420             }
421             if (!parms[i])      /* make sure there's space */
422                 parms[i] = (char *)malloc(BOZO_BSSIZE);
423             strcpy(parms[i], tbuffer + 5);      /* remember the parameter for later */
424             thisparms[i] = parms[i];
425         }
426
427         /* ok, we have the type and parms, now create the object */
428         code =
429             bnode_Create(typep, instp, &tb, thisparms[0], thisparms[1],
430                          thisparms[2], thisparms[3], thisparms[4], notifier,
431                          goal ? BSTAT_NORMAL : BSTAT_SHUTDOWN, 0);
432         if (code)
433             goto fail;
434
435         /* bnode created in 'temporarily shutdown' state;
436          * check to see if we are supposed to run this guy,
437          * and if so, start the process up */
438         if (goal) {
439             bnode_SetStat(tb, BSTAT_NORMAL);    /* set goal, taking effect immediately */
440         } else {
441             bnode_SetStat(tb, BSTAT_SHUTDOWN);
442         }
443     }
444     /* all done */
445     code = 0;
446
447   fail:
448     if (instp)
449         free(instp);
450     if (typep)
451         free(typep);
452     for (i = 0; i < MAXPARMS; i++)
453         if (parms[i])
454             free(parms[i]);
455     if (tfile)
456         fclose(tfile);
457     return code;
458 }
459
460 /* write a new bozo file */
461 int
462 WriteBozoFile(char *aname)
463 {
464     FILE *tfile;
465     char tbuffer[AFSDIR_PATH_MAX];
466     afs_int32 code;
467     struct bztemp btemp;
468
469     if (!aname)
470         aname = (char *)bozo_fileName;
471     strcpy(tbuffer, aname);
472     strcat(tbuffer, ".NBZ");
473     tfile = fopen(tbuffer, "w");
474     if (!tfile)
475         return -1;
476     btemp.file = tfile;
477
478     fprintf(tfile, "restrictmode %d\n", bozo_isrestricted);
479     fprintf(tfile, "restarttime %d %d %d %d %d\n", bozo_nextRestartKT.mask,
480             bozo_nextRestartKT.day, bozo_nextRestartKT.hour,
481             bozo_nextRestartKT.min, bozo_nextRestartKT.sec);
482     fprintf(tfile, "checkbintime %d %d %d %d %d\n", bozo_nextDayKT.mask,
483             bozo_nextDayKT.day, bozo_nextDayKT.hour, bozo_nextDayKT.min,
484             bozo_nextDayKT.sec);
485     code = bnode_ApplyInstance(bzwrite, &btemp);
486     if (code || (code = ferror(tfile))) {       /* something went wrong */
487         fclose(tfile);
488         unlink(tbuffer);
489         return code;
490     }
491     /* close the file, check for errors and snap new file into place */
492     if (fclose(tfile) == EOF) {
493         unlink(tbuffer);
494         return -1;
495     }
496     code = renamefile(tbuffer, aname);
497     if (code) {
498         unlink(tbuffer);
499         return -1;
500     }
501     return 0;
502 }
503
504 static int
505 bdrestart(struct bnode *abnode, void *arock)
506 {
507     afs_int32 code;
508
509     if (abnode->fileGoal != BSTAT_NORMAL || abnode->goal != BSTAT_NORMAL)
510         return 0;               /* don't restart stopped bnodes */
511     bnode_Hold(abnode);
512     code = bnode_RestartP(abnode);
513     if (code) {
514         /* restart the dude */
515         bnode_SetStat(abnode, BSTAT_SHUTDOWN);
516         bnode_WaitStatus(abnode, BSTAT_SHUTDOWN);
517         bnode_SetStat(abnode, BSTAT_NORMAL);
518     }
519     bnode_Release(abnode);
520     return 0;                   /* keep trying all bnodes */
521 }
522
523 #define BOZO_MINSKIP 3600       /* minimum to advance clock */
524 /* lwp to handle system restarts */
525 static void *
526 BozoDaemon(void *unused)
527 {
528     afs_int32 now;
529
530     /* now initialize the values */
531     bozo_newKTs = 1;
532     while (1) {
533         IOMGR_Sleep(60);
534         now = FT_ApproxTime();
535
536         if (bozo_restdisable) {
537             bozo_Log("Restricted mode disabled by signal\n");
538             bozo_restdisable = 0;
539         }
540
541         if (bozo_newKTs) {      /* need to recompute restart times */
542             bozo_newKTs = 0;    /* done for a while */
543             nextRestart = ktime_next(&bozo_nextRestartKT, BOZO_MINSKIP);
544             nextDay = ktime_next(&bozo_nextDayKT, BOZO_MINSKIP);
545         }
546
547         /* see if we should do a restart */
548         if (now > nextRestart) {
549             SBOZO_ReBozo(0);    /* doesn't come back */
550         }
551
552         /* see if we should restart a server */
553         if (now > nextDay) {
554             nextDay = ktime_next(&bozo_nextDayKT, BOZO_MINSKIP);
555
556             /* call the bnode restartp function, and restart all that require it */
557             bnode_ApplyInstance(bdrestart, 0);
558         }
559     }
560     return NULL;
561 }
562
563 #ifdef AFS_AIX32_ENV
564 static int
565 tweak_config(void)
566 {
567     FILE *f;
568     char c[80];
569     int s, sb_max, ipfragttl;
570
571     sb_max = 131072;
572     ipfragttl = 20;
573     f = popen("/usr/sbin/no -o sb_max", "r");
574     s = fscanf(f, "sb_max = %d", &sb_max);
575     fclose(f);
576     if (s < 1)
577         return;
578     f = popen("/usr/sbin/no -o ipfragttl", "r");
579     s = fscanf(f, "ipfragttl = %d", &ipfragttl);
580     fclose(f);
581     if (s < 1)
582         ipfragttl = 20;
583
584     if (sb_max < 131072)
585         sb_max = 131072;
586     if (ipfragttl > 20)
587         ipfragttl = 20;
588
589     sprintf(c, "/usr/sbin/no -o sb_max=%d -o ipfragttl=%d", sb_max,
590             ipfragttl);
591     f = popen(c, "r");
592     fclose(f);
593 }
594 #endif
595
596 #if 0
597 /*
598  * This routine causes the calling process to go into the background and
599  * to lose its controlling tty.
600  *
601  * It does not close or otherwise alter the standard file descriptors.
602  *
603  * It writes warning messages to the standard error output if certain
604  * fundamental errors occur.
605  *
606  * This routine requires
607  *
608  * #include <sys/types.h>
609  * #include <sys/stat.h>
610  * #include <fcntl.h>
611  * #include <unistd.h>
612  * #include <stdlib.h>
613  *
614  * and has been tested on:
615  *
616  * AIX 4.2
617  * Digital Unix 4.0D
618  * HP-UX 11.0
619  * IRIX 6.5
620  * Linux 2.1.125
621  * Solaris 2.5
622  * Solaris 2.6
623  */
624
625 #ifndef AFS_NT40_ENV
626 static void
627 background(void)
628 {
629     /*
630      * A process is a process group leader if its process ID
631      * (getpid()) and its process group ID (getpgrp()) are the same.
632      */
633
634     /*
635      * To create a new session (and thereby lose our controlling
636      * terminal) we cannot be a process group leader.
637      *
638      * To guarantee we are not a process group leader, we fork and
639      * let the parent process exit.
640      */
641
642     if (getpid() == getpgrp()) {
643         pid_t pid;
644         pid = fork();
645         switch (pid) {
646         case -1:
647             abort();            /* leave footprints */
648             break;
649         case 0:         /* child */
650             break;
651         default:                /* parent */
652             exit(0);
653             break;
654         }
655     }
656
657     /*
658      * By here, we are not a process group leader, so we can make a
659      * new session and become the session leader.
660      */
661
662     {
663         pid_t sid = setsid();
664
665         if (sid == -1) {
666             static char err[] = "bosserver: WARNING: setsid() failed\n";
667             write(STDERR_FILENO, err, sizeof err - 1);
668         }
669     }
670
671     /*
672      * Once we create a new session, the current process is a
673      * session leader without a controlling tty.
674      *
675      * On some systems, the first tty device the session leader
676      * opens automatically becomes the controlling tty for the
677      * session.
678      *
679      * So, to guarantee we do not acquire a controlling tty, we fork
680      * and let the parent process exit.  The child process is not a
681      * session leader, and so it will not acquire a controlling tty
682      * even if it should happen to open a tty device.
683      */
684
685     if (getpid() == getpgrp()) {
686         pid_t pid;
687         pid = fork();
688         switch (pid) {
689         case -1:
690             abort();            /* leave footprints */
691             break;
692         case 0:         /* child */
693             break;
694         default:                /* parent */
695             exit(0);
696             break;
697         }
698     }
699
700     /*
701      * check that we no longer have a controlling tty
702      */
703
704     {
705         int fd;
706
707         fd = open("/dev/tty", O_RDONLY);
708
709         if (fd >= 0) {
710             static char err[] =
711                 "bosserver: WARNING: /dev/tty still attached\n";
712             close(fd);
713             write(STDERR_FILENO, err, sizeof err - 1);
714         }
715     }
716 }
717 #endif /* ! AFS_NT40_ENV */
718 #endif
719
720 static char *
721 make_pid_filename(char *ainst, char *aname)
722 {
723     char *buffer = NULL;
724     int length;
725
726     length = strlen(DoPidFiles) + strlen(ainst) + 6;
727     if (aname && *aname) {
728         length += strlen(aname) + 1;
729     }
730     buffer = malloc(length * sizeof(char));
731     if (!buffer) {
732         if (aname) {
733             bozo_Log("Failed to alloc pid filename buffer for %s.%s.\n",
734                      ainst, aname);
735         } else {
736             bozo_Log("Failed to alloc pid filename buffer for %s.\n", ainst);
737         }
738     } else {
739         if (aname && *aname) {
740             snprintf(buffer, length, "%s/%s.%s.pid", DoPidFiles, ainst,
741                      aname);
742         } else {
743             snprintf(buffer, length, "%s/%s.pid", DoPidFiles, ainst);
744         }
745     }
746     return buffer;
747 }
748
749 /**
750  * Write a file containing the pid of the named process.
751  *
752  * @param ainst instance name
753  * @param aname sub-process name of the instance, may be null
754  * @param apid  process id of the newly started process
755  *
756  * @returns status
757  */
758 int
759 bozo_CreatePidFile(char *ainst, char *aname, pid_t apid)
760 {
761     int code = 0;
762     char *pidfile = NULL;
763     FILE *fp;
764
765     pidfile = make_pid_filename(ainst, aname);
766     if (!pidfile) {
767         return ENOMEM;
768     }
769     if ((fp = fopen(pidfile, "w")) == NULL) {
770         bozo_Log("Failed to open pidfile %s; errno=%d\n", pidfile, errno);
771         free(pidfile);
772         return errno;
773     }
774     if (fprintf(fp, "%ld\n", afs_printable_int32_ld(apid)) < 0) {
775         code = errno;
776     }
777     if (fclose(fp) != 0) {
778         code = errno;
779     }
780     free(pidfile);
781     return code;
782 }
783
784 /**
785  * Clean a pid file for a process which just exited.
786  *
787  * @param ainst instance name
788  * @param aname sub-process name of the instance, may be null
789  *
790  * @returns status
791  */
792 int
793 bozo_DeletePidFile(char *ainst, char *aname)
794 {
795     char *pidfile = NULL;
796     pidfile = make_pid_filename(ainst, aname);
797     if (pidfile) {
798         unlink(pidfile);
799         free(pidfile);
800     }
801     return 0;
802 }
803
804 /**
805  * Create the rxbind file of this bosserver.
806  *
807  * @param host  bind address of this server
808  *
809  * @returns status
810  */
811 void
812 bozo_CreateRxBindFile(afs_uint32 host)
813 {
814     char buffer[16];
815     FILE *fp;
816
817     if (host == htonl(INADDR_ANY)) {
818         host = htonl(0x7f000001);
819     }
820
821     afs_inet_ntoa_r(host, buffer);
822     bozo_Log("Listening on %s:%d\n", buffer, AFSCONF_NANNYPORT);
823     if ((fp = fopen(AFSDIR_SERVER_BOZRXBIND_FILEPATH, "w")) == NULL) {
824         bozo_Log("Unable to open rxbind address file: %s, code=%d\n",
825                  AFSDIR_SERVER_BOZRXBIND_FILEPATH, errno);
826     } else {
827         fprintf(fp, "%s\n", buffer);
828         fclose(fp);
829     }
830 }
831
832 /* start a process and monitor it */
833
834 #include "AFS_component_version_number.c"
835
836 int
837 main(int argc, char **argv, char **envp)
838 {
839     struct rx_service *tservice;
840     afs_int32 code;
841     struct afsconf_dir *tdir;
842     int noAuth = 0;
843     int i;
844     char namebuf[AFSDIR_PATH_MAX];
845     int rxMaxMTU = -1;
846     afs_uint32 host = htonl(INADDR_ANY);
847     char *auditFileName = NULL;
848     struct rx_securityClass **securityClasses;
849     afs_int32 numClasses;
850 #ifndef AFS_NT40_ENV
851     int nofork = 0;
852     struct stat sb;
853 #endif
854 #ifdef  AFS_AIX32_ENV
855     struct sigaction nsa;
856
857     /* for some reason, this permits user-mode RX to run a lot faster.
858      * we do it here in the bosserver, so we don't have to do it
859      * individually in each server.
860      */
861     tweak_config();
862
863     /*
864      * The following signal action for AIX is necessary so that in case of a
865      * crash (i.e. core is generated) we can include the user's data section
866      * in the core dump. Unfortunately, by default, only a partial core is
867      * generated which, in many cases, isn't too useful.
868      */
869     sigemptyset(&nsa.sa_mask);
870     nsa.sa_handler = SIG_DFL;
871     nsa.sa_flags = SA_FULLDUMP;
872     sigaction(SIGSEGV, &nsa, NULL);
873     sigaction(SIGABRT, &nsa, NULL);
874 #endif
875     osi_audit_init();
876     signal(SIGFPE, bozo_insecureme);
877
878 #ifdef AFS_NT40_ENV
879     /* Initialize winsock */
880     if (afs_winsockInit() < 0) {
881         ReportErrorEventAlt(AFSEVT_SVR_WINSOCK_INIT_FAILED, 0, argv[0], 0);
882         fprintf(stderr, "%s: Couldn't initialize winsock.\n", argv[0]);
883         exit(2);
884     }
885 #endif
886
887     /* Initialize dirpaths */
888     if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) {
889 #ifdef AFS_NT40_ENV
890         ReportErrorEventAlt(AFSEVT_SVR_NO_INSTALL_DIR, 0, argv[0], 0);
891 #endif
892         fprintf(stderr, "%s: Unable to obtain AFS server directory.\n",
893                 argv[0]);
894         exit(2);
895     }
896
897     /* some path inits */
898     bozo_fileName = AFSDIR_SERVER_BOZCONF_FILEPATH;
899     DoCore = AFSDIR_SERVER_LOGS_DIRPATH;
900
901     /* initialize the list of dirpaths that the bosserver has
902      * an interest in monitoring */
903     initBosEntryStats();
904
905 #if defined(AFS_SGI_ENV)
906     /* offer some protection if AFS isn't loaded */
907     if (syscall(AFS_SYSCALL, AFSOP_ENDLOG) < 0 && errno == ENOPKG) {
908         printf("bosserver: AFS doesn't appear to be configured in O.S..\n");
909         exit(1);
910     }
911 #endif
912
913     /* parse cmd line */
914     for (code = 1; code < argc; code++) {
915         if (strcmp(argv[code], "-noauth") == 0) {
916             /* set noauth flag */
917             noAuth = 1;
918         } else if (strcmp(argv[code], "-log") == 0) {
919             /* set extra logging flag */
920             DoLogging = 1;
921         }
922 #ifndef AFS_NT40_ENV
923         else if (strcmp(argv[code], "-syslog") == 0) {
924             /* set syslog logging flag */
925             DoSyslog = 1;
926         } else if (strncmp(argv[code], "-syslog=", 8) == 0) {
927             DoSyslog = 1;
928             DoSyslogFacility = atoi(argv[code] + 8);
929         } else if (strncmp(argv[code], "-cores=", 7) == 0) {
930             if (strcmp((argv[code]+7), "none") == 0)
931                 DoCore = 0;
932             else
933                 DoCore = (argv[code]+7);
934         } else if (strcmp(argv[code], "-nofork") == 0) {
935             nofork = 1;
936         }
937 #endif
938         else if (strcmp(argv[code], "-enable_peer_stats") == 0) {
939             rx_enablePeerRPCStats();
940         } else if (strcmp(argv[code], "-enable_process_stats") == 0) {
941             rx_enableProcessRPCStats();
942         }
943         else if (strcmp(argv[code], "-restricted") == 0) {
944             bozo_isrestricted = 1;
945         }
946         else if (strcmp(argv[code], "-rxbind") == 0) {
947             rxBind = 1;
948         }
949         else if (strcmp(argv[code], "-allow-dotted-principals") == 0) {
950             rxkadDisableDotCheck = 1;
951         }
952         else if (!strcmp(argv[code], "-rxmaxmtu")) {
953             if ((code + 1) >= argc) {
954                 fprintf(stderr, "missing argument for -rxmaxmtu\n");
955                 exit(1);
956             }
957             rxMaxMTU = atoi(argv[++code]);
958             if ((rxMaxMTU < RX_MIN_PACKET_SIZE) ||
959                 (rxMaxMTU > RX_MAX_PACKET_DATA_SIZE)) {
960                 printf("rxMaxMTU %d invalid; must be between %d-%" AFS_SIZET_FMT "\n",
961                         rxMaxMTU, RX_MIN_PACKET_SIZE,
962                         RX_MAX_PACKET_DATA_SIZE);
963                 exit(1);
964             }
965         }
966         else if (strcmp(argv[code], "-auditlog") == 0) {
967             auditFileName = argv[++code];
968
969         } else if (strcmp(argv[code], "-audit-interface") == 0) {
970             char *interface = argv[++code];
971
972             if (osi_audit_interface(interface)) {
973                 printf("Invalid audit interface '%s'\n", interface);
974                 exit(1);
975             }
976         } else if (strncmp(argv[code], "-pidfiles=", 10) == 0) {
977             DoPidFiles = (argv[code]+10);
978         } else if (strncmp(argv[code], "-pidfiles", 9) == 0) {
979             DoPidFiles = AFSDIR_BOSCONFIG_DIR;
980         }
981         else {
982
983             /* hack to support help flag */
984
985 #ifndef AFS_NT40_ENV
986             printf("Usage: bosserver [-noauth] [-log] "
987                    "[-auditlog <log path>] "
988                    "[-audit-interafce <file|sysvmq> (default is file)] "
989                    "[-rxmaxmtu <bytes>] [-rxbind] [-allow-dotted-principals]"
990                    "[-syslog[=FACILITY]] "
991                    "[-enable_peer_stats] [-enable_process_stats] "
992                    "[-cores=<none|path>] \n"
993                    "[-pidfiles[=path]] "
994                    "[-nofork] " "[-help]\n");
995 #else
996             printf("Usage: bosserver [-noauth] [-log] "
997                    "[-auditlog <log path>] "
998                    "[-audit-interafce <file|sysvmq> (default is file)] "
999                    "[-rxmaxmtu <bytes>] [-rxbind] [-allow-dotted-principals]"
1000                    "[-enable_peer_stats] [-enable_process_stats] "
1001                    "[-cores=<none|path>] \n"
1002                    "[-pidfiles[=path]] "
1003                    "[-help]\n");
1004 #endif
1005             fflush(stdout);
1006
1007             exit(0);
1008         }
1009     }
1010     if (auditFileName) {
1011         osi_audit_file(auditFileName);
1012     }
1013
1014 #ifndef AFS_NT40_ENV
1015     if (geteuid() != 0) {
1016         printf("bosserver: must be run as root.\n");
1017         exit(1);
1018     }
1019 #endif
1020
1021     code = bnode_Init();
1022     if (code) {
1023         printf("bosserver: could not init bnode package, code %d\n", code);
1024         exit(1);
1025     }
1026
1027     bnode_Register("fs", &fsbnode_ops, 3);
1028     bnode_Register("dafs", &dafsbnode_ops, 4);
1029     bnode_Register("simple", &ezbnode_ops, 1);
1030     bnode_Register("cron", &cronbnode_ops, 2);
1031
1032     /* create useful dirs */
1033     CreateDirs(DoCore);
1034
1035     /* chdir to AFS log directory */
1036     if (DoCore)
1037         chdir(DoCore);
1038     else
1039         chdir(AFSDIR_SERVER_LOGS_DIRPATH);
1040
1041 #if 0
1042     fputs(AFS_GOVERNMENT_MESSAGE, stdout);
1043     fflush(stdout);
1044 #endif
1045
1046     /* go into the background and remove our controlling tty, close open
1047        file desriptors
1048      */
1049
1050 #ifndef AFS_NT40_ENV
1051     if (!nofork)
1052         daemon(1, 0);
1053 #endif /* ! AFS_NT40_ENV */
1054
1055     if ((!DoSyslog)
1056 #ifndef AFS_NT40_ENV
1057         && ((lstat(AFSDIR_BOZLOG_FILE, &sb) == 0) &&
1058         !(S_ISFIFO(sb.st_mode)))
1059 #endif
1060         ) {
1061         strcpy(namebuf, AFSDIR_BOZLOG_FILE);
1062         strcat(namebuf, ".old");
1063         renamefile(AFSDIR_BOZLOG_FILE, namebuf);        /* try rename first */
1064         bozo_logFile = fopen(AFSDIR_BOZLOG_FILE, "a");
1065         if (!bozo_logFile) {
1066             printf("bosserver: can't initialize log file (%s).\n",
1067                    AFSDIR_SERVER_BOZLOG_FILEPATH);
1068             exit(1);
1069         }
1070         /* keep log closed normally, so can be removed */
1071         fclose(bozo_logFile);
1072     } else {
1073 #ifndef AFS_NT40_ENV
1074         openlog("bosserver", LOG_PID, DoSyslogFacility);
1075 #endif
1076     }
1077
1078 #if defined(RLIMIT_CORE) && defined(HAVE_GETRLIMIT)
1079     {
1080       struct rlimit rlp;
1081       getrlimit(RLIMIT_CORE, &rlp);
1082       if (!DoCore)
1083           rlp.rlim_cur = 0;
1084       else
1085           rlp.rlim_max = rlp.rlim_cur = RLIM_INFINITY;
1086       setrlimit(RLIMIT_CORE, &rlp);
1087       getrlimit(RLIMIT_CORE, &rlp);
1088       bozo_Log("Core limits now %d %d\n",(int)rlp.rlim_cur,(int)rlp.rlim_max);
1089     }
1090 #endif
1091
1092     /* Write current state of directory permissions to log file */
1093     DirAccessOK();
1094
1095     if (rxBind) {
1096         afs_int32 ccode;
1097         if (AFSDIR_SERVER_NETRESTRICT_FILEPATH ||
1098             AFSDIR_SERVER_NETINFO_FILEPATH) {
1099             char reason[1024];
1100             ccode = parseNetFiles(SHostAddrs, NULL, NULL,
1101                                   ADDRSPERSITE, reason,
1102                                   AFSDIR_SERVER_NETINFO_FILEPATH,
1103                                   AFSDIR_SERVER_NETRESTRICT_FILEPATH);
1104         } else {
1105             ccode = rx_getAllAddr(SHostAddrs, ADDRSPERSITE);
1106         }
1107         if (ccode == 1)
1108             host = SHostAddrs[0];
1109     }
1110
1111     for (i = 0; i < 10; i++) {
1112         if (rxBind) {
1113             code = rx_InitHost(host, htons(AFSCONF_NANNYPORT));
1114         } else {
1115             code = rx_Init(htons(AFSCONF_NANNYPORT));
1116         }
1117         if (code) {
1118             bozo_Log("can't initialize rx: code=%d\n", code);
1119             sleep(3);
1120         } else
1121             break;
1122     }
1123     if (i >= 10) {
1124         bozo_Log("Bos giving up, can't initialize rx\n");
1125         exit(code);
1126     }
1127
1128     code = LWP_CreateProcess(BozoDaemon, BOZO_LWP_STACKSIZE, /* priority */ 1,
1129                              /* param */ NULL , "bozo-the-clown",
1130                              &bozo_pid);
1131
1132     /* try to read the key from the config file */
1133     tdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
1134     if (!tdir) {
1135         /* try to create local cell config file */
1136         struct afsconf_cell tcell;
1137         strcpy(tcell.name, "localcell");
1138         tcell.numServers = 1;
1139         code = gethostname(tcell.hostName[0], MAXHOSTCHARS);
1140         if (code) {
1141             bozo_Log("failed to get hostname, code %d\n", errno);
1142             exit(1);
1143         }
1144         if (tcell.hostName[0][0] == 0) {
1145             bozo_Log("host name not set, can't start\n");
1146             bozo_Log("try the 'hostname' command\n");
1147             exit(1);
1148         }
1149         memset(tcell.hostAddr, 0, sizeof(tcell.hostAddr));      /* not computed */
1150         code =
1151             afsconf_SetCellInfo(bozo_confdir, AFSDIR_SERVER_ETC_DIRPATH,
1152                                 &tcell);
1153         if (code) {
1154             bozo_Log
1155                 ("could not create cell database in '%s' (code %d), quitting\n",
1156                  AFSDIR_SERVER_ETC_DIRPATH, code);
1157             exit(1);
1158         }
1159         tdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
1160         if (!tdir) {
1161             bozo_Log
1162                 ("failed to open newly-created cell database, quitting\n");
1163             exit(1);
1164         }
1165     }
1166
1167     /* read init file, starting up programs */
1168     if ((code = ReadBozoFile(0))) {
1169         bozo_Log
1170             ("bosserver: Something is wrong (%d) with the bos configuration file %s; aborting\n",
1171              code, AFSDIR_SERVER_BOZCONF_FILEPATH);
1172         exit(code);
1173     }
1174
1175     bozo_CreateRxBindFile(host);        /* for local scripts */
1176
1177     /* opened the cell databse */
1178     bozo_confdir = tdir;
1179
1180     /* allow super users to manage RX statistics */
1181     rx_SetRxStatUserOk(bozo_rxstat_userok);
1182
1183     afsconf_SetNoAuthFlag(tdir, noAuth);
1184     afsconf_BuildServerSecurityObjects(tdir, &securityClasses, &numClasses);
1185
1186     if (DoPidFiles) {
1187         bozo_CreatePidFile("bosserver", NULL, getpid());
1188     }
1189
1190     /* Disable jumbograms */
1191     rx_SetNoJumbo();
1192
1193     if (rxMaxMTU != -1) {
1194         rx_SetMaxMTU(rxMaxMTU);
1195     }
1196
1197     tservice = rx_NewServiceHost(host, 0, /* service id */ 1,
1198                                  "bozo", securityClasses, numClasses,
1199                                  BOZO_ExecuteRequest);
1200     rx_SetMinProcs(tservice, 2);
1201     rx_SetMaxProcs(tservice, 4);
1202     rx_SetStackSize(tservice, BOZO_LWP_STACKSIZE);      /* so gethostbyname works (in cell stuff) */
1203     if (rxkadDisableDotCheck) {
1204         rx_SetSecurityConfiguration(tservice, RXS_CONFIG_FLAGS,
1205                                     (void *)RXS_CONFIG_FLAGS_DISABLE_DOTCHECK);
1206     }
1207
1208     tservice =
1209         rx_NewServiceHost(host, 0, RX_STATS_SERVICE_ID, "rpcstats",
1210                           securityClasses, numClasses, RXSTATS_ExecuteRequest);
1211     rx_SetMinProcs(tservice, 2);
1212     rx_SetMaxProcs(tservice, 4);
1213     rx_StartServer(1);          /* donate this process */
1214     return 0;
1215 }
1216
1217 void
1218 bozo_Log(char *format, ...)
1219 {
1220     char tdate[27];
1221     time_t myTime;
1222     va_list ap;
1223
1224     va_start(ap, format);
1225
1226     if (DoSyslog) {
1227 #ifndef AFS_NT40_ENV
1228         vsyslog(LOG_INFO, format, ap);
1229 #endif
1230     } else {
1231         myTime = time(0);
1232         strcpy(tdate, ctime(&myTime));  /* copy out of static area asap */
1233         tdate[24] = ':';
1234
1235         /* log normally closed, so can be removed */
1236
1237         bozo_logFile = fopen(AFSDIR_SERVER_BOZLOG_FILEPATH, "a");
1238         if (bozo_logFile == NULL) {
1239             printf("bosserver: WARNING: problem with %s\n",
1240                    AFSDIR_SERVER_BOZLOG_FILEPATH);
1241             printf("%s ", tdate);
1242             vprintf(format, ap);
1243             fflush(stdout);
1244         } else {
1245             fprintf(bozo_logFile, "%s ", tdate);
1246             vfprintf(bozo_logFile, format, ap);
1247
1248             /* close so rm BosLog works */
1249             fclose(bozo_logFile);
1250         }
1251     }
1252 }