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