Import Upstream version 1.8.5
[hcoop/debian/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 code = bnode_Init();
1120 if (code) {
1121 printf("bosserver: could not init bnode package, code %d\n", code);
1122 exit(1);
1123 }
1124
1125 bnode_Register("fs", &fsbnode_ops, 3);
1126 bnode_Register("dafs", &dafsbnode_ops, 4);
1127 bnode_Register("simple", &ezbnode_ops, 1);
1128 bnode_Register("cron", &cronbnode_ops, 2);
1129
1130 #if defined(RLIMIT_CORE) && defined(HAVE_GETRLIMIT)
1131 {
1132 struct rlimit rlp;
1133 getrlimit(RLIMIT_CORE, &rlp);
1134 if (!DoCore)
1135 rlp.rlim_cur = 0;
1136 else
1137 rlp.rlim_max = rlp.rlim_cur = RLIM_INFINITY;
1138 setrlimit(RLIMIT_CORE, &rlp);
1139 getrlimit(RLIMIT_CORE, &rlp);
1140 bozo_Log("Core limits now %d %d\n",(int)rlp.rlim_cur,(int)rlp.rlim_max);
1141 }
1142 #endif
1143
1144 /* Read init file, starting up programs. Also starts watcher threads. */
1145 if ((code = ReadBozoFile(0))) {
1146 bozo_Log
1147 ("bosserver: Something is wrong (%d) with the bos configuration file %s; aborting\n",
1148 code, AFSDIR_SERVER_BOZCONF_FILEPATH);
1149 exit(code);
1150 }
1151
1152 if (rxBind) {
1153 host = GetRxBindAddress();
1154 }
1155 for (i = 0; i < 10; i++) {
1156 if (rxBind) {
1157 code = rx_InitHost(host, htons(AFSCONF_NANNYPORT));
1158 } else {
1159 code = rx_Init(htons(AFSCONF_NANNYPORT));
1160 }
1161 if (code) {
1162 bozo_Log("can't initialize rx: code=%d\n", code);
1163 sleep(3);
1164 } else
1165 break;
1166 }
1167 if (i >= 10) {
1168 bozo_Log("Bos giving up, can't initialize rx\n");
1169 exit(code);
1170 }
1171
1172 /* Set some rx config */
1173 if (DoPeerRPCStats)
1174 rx_enablePeerRPCStats();
1175 if (DoProcessRPCStats)
1176 rx_enableProcessRPCStats();
1177
1178 /* Disable jumbograms */
1179 rx_SetNoJumbo();
1180
1181 if (rxMaxMTU != -1) {
1182 if (rx_SetMaxMTU(rxMaxMTU) != 0) {
1183 bozo_Log("bosserver: rxMaxMTU %d is invalid\n", rxMaxMTU);
1184 exit(1);
1185 }
1186 }
1187
1188 code = LWP_CreateProcess(BozoDaemon, BOZO_LWP_STACKSIZE, /* priority */ 1,
1189 /* param */ NULL , "bozo-the-clown", &bozo_pid);
1190 if (code) {
1191 bozo_Log("Failed to create daemon thread\n");
1192 exit(1);
1193 }
1194
1195 /* initialize audit user check */
1196 osi_audit_set_user_check(bozo_confdir, bozo_IsLocalRealmMatch);
1197
1198 bozo_CreateRxBindFile(host); /* for local scripts */
1199
1200 /* allow super users to manage RX statistics */
1201 rx_SetRxStatUserOk(bozo_rxstat_userok);
1202
1203 afsconf_SetNoAuthFlag(tdir, noAuth);
1204 afsconf_BuildServerSecurityObjects(tdir, &securityClasses, &numClasses);
1205
1206 if (DoPidFiles) {
1207 bozo_CreatePidFile("bosserver", NULL, getpid());
1208 }
1209
1210 tservice = rx_NewServiceHost(host, 0, /* service id */ 1,
1211 "bozo", securityClasses, numClasses,
1212 BOZO_ExecuteRequest);
1213 rx_SetMinProcs(tservice, 2);
1214 rx_SetMaxProcs(tservice, 4);
1215 rx_SetStackSize(tservice, BOZO_LWP_STACKSIZE); /* so gethostbyname works (in cell stuff) */
1216 if (rxkadDisableDotCheck) {
1217 rx_SetSecurityConfiguration(tservice, RXS_CONFIG_FLAGS,
1218 (void *)RXS_CONFIG_FLAGS_DISABLE_DOTCHECK);
1219 }
1220
1221 tservice =
1222 rx_NewServiceHost(host, 0, RX_STATS_SERVICE_ID, "rpcstats",
1223 securityClasses, numClasses, RXSTATS_ExecuteRequest);
1224 rx_SetMinProcs(tservice, 2);
1225 rx_SetMaxProcs(tservice, 4);
1226 rx_StartServer(1); /* donate this process */
1227 return 0;
1228 }
1229
1230 void
1231 bozo_Log(const char *format, ...)
1232 {
1233 char tdate[27];
1234 time_t myTime;
1235 va_list ap;
1236
1237 va_start(ap, format);
1238
1239 if (DoSyslog) {
1240 #ifndef AFS_NT40_ENV
1241 vsyslog(LOG_INFO, format, ap);
1242 #endif
1243 } else {
1244 myTime = time(0);
1245 strcpy(tdate, ctime(&myTime)); /* copy out of static area asap */
1246 tdate[24] = ':';
1247
1248 /* log normally closed, so can be removed */
1249
1250 bozo_logFile = fopen(AFSDIR_SERVER_BOZLOG_FILEPATH, "a");
1251 if (bozo_logFile == NULL) {
1252 printf("bosserver: WARNING: problem with %s\n",
1253 AFSDIR_SERVER_BOZLOG_FILEPATH);
1254 printf("%s ", tdate);
1255 vprintf(format, ap);
1256 fflush(stdout);
1257 } else {
1258 fprintf(bozo_logFile, "%s ", tdate);
1259 vfprintf(bozo_logFile, format, ap);
1260
1261 /* close so rm BosLog works */
1262 fclose(bozo_logFile);
1263 }
1264 }
1265 va_end(ap);
1266 }