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