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