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