bozo: Add KeyFileExt and rxkad.keytab to access rights check
[openafs.git] / src / bozo / bosoprocs.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 <roken.h>
15
16 #ifdef AFS_NT40_ENV
17 #include <sys/utime.h>
18 #endif /* AFS_NT40_ENV */
19
20 #include <rx/xdr.h>
21 #include <rx/rx.h>
22 #include <rx/rxkad.h>
23 #include <afs/cellconfig.h>
24 #include <afs/keys.h>
25 #include <afs/afsutil.h>
26 #include <afs/fileutil.h>
27 #include <afs/ktime.h>
28 #include <afs/audit.h>
29 #include <afs/kautils.h>
30
31 #include "bnode.h"
32 #include "bnode_internal.h"
33 #include "bosint.h"
34 #include "bosprototypes.h"
35
36 extern struct ktime bozo_nextRestartKT, bozo_nextDayKT;
37
38 extern struct afsconf_dir *bozo_confdir;
39 extern int bozo_newKTs;
40 extern int DoLogging;
41 extern int bozo_isrestricted;
42
43 afs_int32
44 SBOZO_GetRestartTime(struct rx_call *acall, afs_int32 atype, struct bozo_netKTime *aktime)
45 {
46     afs_int32 code;
47
48     code = 0;                   /* assume success */
49     switch (atype) {
50     case 1:
51         memcpy(aktime, &bozo_nextRestartKT, sizeof(struct ktime));
52         break;
53
54     case 2:
55         memcpy(aktime, &bozo_nextDayKT, sizeof(struct ktime));
56         break;
57
58     default:
59         code = BZDOM;
60         break;
61     }
62
63     return code;
64 }
65
66 afs_int32
67 SBOZO_SetRestartTime(struct rx_call *acall, afs_int32 atype, struct bozo_netKTime *aktime)
68 {
69     afs_int32 code;
70     char caller[MAXKTCNAMELEN];
71
72     /* check for proper permissions */
73     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
74         code = BZACCESS;
75         goto fail;
76     }
77     if (DoLogging)
78         bozo_Log("%s is executing SetRestartTime\n", caller);
79
80     code = 0;                   /* assume success */
81     switch (atype) {
82     case 1:
83         memcpy(&bozo_nextRestartKT, aktime, sizeof(struct ktime));
84         break;
85
86     case 2:
87         memcpy(&bozo_nextDayKT, aktime, sizeof(struct ktime));
88         break;
89
90     default:
91         code = BZDOM;
92         break;
93     }
94
95     if (code == 0) {
96         /* try to update the bozo init file */
97         code = WriteBozoFile(0);
98         bozo_newKTs = 1;
99     }
100
101   fail:
102     osi_auditU(acall, BOS_SetRestartEvent, code, AUD_END);
103     return code;
104 }
105
106 afs_int32
107 SBOZO_Exec(struct rx_call *acall, char *acmd)
108 {
109
110     char caller[MAXKTCNAMELEN];
111     int code;
112
113     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
114         code = BZACCESS;
115         goto fail;
116     }
117     if (bozo_isrestricted) {
118         code = BZACCESS;
119         goto fail;
120     }
121     if (DoLogging)
122         bozo_Log("%s is executing the shell command '%s'\n", caller, acmd);
123
124     /* should copy output to acall, but don't yet cause its hard */
125     /*  hard... NOT!  Nnow _at least_ return the exit status */
126     code = system(acmd);
127     osi_auditU(acall, BOS_ExecEvent, code, AUD_STR, acmd, AUD_END);
128
129   fail:
130     return code;
131 }
132
133 afs_int32
134 SBOZO_GetDates(struct rx_call *acall, char *aname, afs_int32 *atime,
135                afs_int32 *abakTime, afs_int32 *aoldTime)
136 {
137     struct stat tstat;
138     char *filepath = NULL, *fpBak = NULL, *fpOld = NULL;
139
140     *atime = *abakTime = *aoldTime = 0;
141
142     /* construct local path from canonical (wire-format) path */
143     if (ConstructLocalBinPath(aname, &filepath)) {
144         return 0;
145     }
146     if (asprintf(&fpBak, "%s.BAK", filepath) < 0) {
147         fpBak = NULL;
148         goto out;
149     }
150     if (asprintf(&fpOld, "%s.OLD", filepath) < 0) {
151         fpOld = NULL;
152         goto out;
153     }
154
155     if (!stat(filepath, &tstat)) {
156         *atime = tstat.st_mtime;
157     }
158
159     if (!stat(fpBak, &tstat)) {
160         *abakTime = tstat.st_mtime;
161     }
162
163     if (!stat(fpOld, &tstat)) {
164         *aoldTime = tstat.st_mtime;
165     }
166 out:
167     free(fpOld);
168     free(fpBak);
169     free(filepath);
170     return 0;
171 }
172
173 afs_int32
174 SBOZO_UnInstall(struct rx_call *acall, char *aname)
175 {
176     char *filepath = NULL;
177     char *fpOld = NULL, *fpBak = NULL;
178     afs_int32 code;
179     char caller[MAXKTCNAMELEN];
180     struct stat tstat;
181
182     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
183         code = BZACCESS;
184         osi_auditU(acall, BOS_UnInstallEvent, code, AUD_STR, aname, AUD_END);
185         return code;
186     }
187     if (bozo_isrestricted) {
188         code = BZACCESS;
189         osi_auditU(acall, BOS_UnInstallEvent, code, AUD_STR, aname, AUD_END);
190         return code;
191     }
192
193     /* construct local path from canonical (wire-format) path */
194     if (ConstructLocalBinPath(aname, &filepath)) {
195         return BZNOENT;
196     }
197
198     if (DoLogging)
199         bozo_Log("%s is executing UnInstall '%s'\n", caller, filepath);
200
201     if (asprintf(&fpBak, "%s.BAK", filepath) < 0) {
202         code = BZIO;
203         fpBak = NULL;
204         goto out;
205     }
206     if (asprintf(&fpOld, "%s.OLD", filepath) < 0) {
207         code = BZIO;
208         fpOld = NULL;
209         goto out;
210     }
211
212     code = rk_rename(fpBak, filepath);
213     if (code) {
214         /* can't find .BAK, try .OLD */
215         code = rk_rename(fpOld, filepath);
216         if (code && errno == ENOENT)    /* If doesn't exist don't fail */
217             code = 0;
218     } else {
219         /* now rename .OLD to .BAK */
220         if (stat(fpOld, &tstat) == 0)
221             code = rk_rename(fpOld, fpBak);
222     }
223     if (code)
224         code = errno;
225
226 out:
227     osi_auditU(acall, BOS_UnInstallEvent, code, AUD_STR, filepath, AUD_END);
228     free(fpBak);
229     free(fpOld);
230     free(filepath);
231
232     return code;
233 }
234
235 #define BOZO_OLDTIME        (7*24*3600) /* 7 days old */
236 static void
237 SaveOldFiles(char *aname)
238 {
239     afs_int32 code;
240     char *bbuffer = NULL, *obuffer = NULL;
241     struct stat tstat;
242     afs_int32 now;
243     afs_int32 oldTime, bakTime;
244
245     now = FT_ApproxTime();
246
247     code = stat(aname, &tstat);
248     if (code < 0)
249         return;                 /* can't stat file */
250
251     if (asprintf(&bbuffer, "%s.BAK", aname) < 0)
252         return;
253
254     if (asprintf(&obuffer, "%s.OLD", aname) < 0) {
255         obuffer = NULL;
256         goto out;
257     }
258
259     code = stat(obuffer, &tstat);       /* discover old file's time */
260     if (code)
261         oldTime = 0;
262     else
263         oldTime = tstat.st_mtime;
264
265     code = stat(bbuffer, &tstat);       /* discover back file's time */
266     if (code)
267         bakTime = 0;
268     else
269         bakTime = tstat.st_mtime;
270
271     if (bakTime && (oldTime == 0 || bakTime < now - BOZO_OLDTIME)) {
272         /* no .OLD file, or .BAK is at least a week old */
273         rk_rename(bbuffer, obuffer);
274     }
275
276     /* finally rename to .BAK extension */
277     rk_rename(aname, bbuffer);
278
279 out:
280     free(bbuffer);
281     free(obuffer);
282 }
283
284 afs_int32
285 SBOZO_Install(struct rx_call *acall, char *aname, afs_int32 asize, afs_int32 mode, afs_int32 amtime)
286 {
287     afs_int32 code, ret = 0;
288     int fd = -1;
289     afs_int32 len;
290     afs_int32 total;
291 #ifdef AFS_NT40_ENV
292     struct _utimbuf utbuf;
293 #else
294     struct timeval tvb[2];
295 #endif
296     char *filepath = NULL, *fpNew = NULL, *tbuffer = NULL;
297     char caller[MAXKTCNAMELEN];
298
299     if (!afsconf_SuperUser(bozo_confdir, acall, caller))
300         return BZACCESS;
301     if (bozo_isrestricted)
302         return BZACCESS;
303
304     /* construct local path from canonical (wire-format) path */
305     if (ConstructLocalBinPath(aname, &filepath)) {
306         return BZNOENT;
307     }
308     if (asprintf(&fpNew, "%s.NEW", filepath) < 0) {
309         ret = ENOMEM;
310         fpNew = NULL;
311         goto out;
312     }
313     tbuffer = malloc(AFSDIR_PATH_MAX);
314     if (tbuffer == NULL) {
315         ret =  ENOMEM;
316         goto out;
317     }
318
319     if (DoLogging)
320         bozo_Log("%s is executing Install '%s'\n", caller, filepath);
321
322     /* open file */
323     fd = open(fpNew, O_CREAT | O_RDWR | O_TRUNC, 0777);
324     if (fd < 0) {
325         ret =  errno;
326         goto out;
327     }
328     total = 0;
329     while (1) {
330         len = rx_Read(acall, tbuffer, sizeof(tbuffer));
331         if (len < 0) {
332             unlink(fpNew);
333             ret =  102;
334             goto out;
335         }
336         if (len == 0)
337             break;              /* no more input */
338         code = write(fd, tbuffer, len);
339         if (code != len) {
340             unlink(fpNew);
341             ret =  100;
342             goto out;
343         }
344         total += len;           /* track total written for safety check at end */
345     }
346     if (asize != total) {
347         unlink(fpNew);
348         ret =  101;             /* wrong size */
349         goto out;
350     }
351
352     /* save old files */
353     SaveOldFiles(filepath);     /* don't care if it works, still install */
354
355     /* all done, rename to final name */
356     code = (rk_rename(fpNew, filepath) ? errno : 0);
357
358     /* label file with same time for our sanity */
359 #ifdef AFS_NT40_ENV
360     utbuf.actime = utbuf.modtime = amtime;
361     _utime(filepath, &utbuf);
362 #else
363     tvb[0].tv_sec = tvb[1].tv_sec = amtime;
364     tvb[0].tv_usec = tvb[1].tv_usec = 0;
365     utimes(filepath, tvb);
366 #endif /* AFS_NT40_ENV */
367
368     if (mode)
369         chmod(filepath, mode);
370
371     if (code < 0) {
372         osi_auditU(acall, BOS_InstallEvent, code, AUD_STR, filepath, AUD_END);
373         ret = errno;
374         goto out;
375     }
376     ret = 0;
377 out:
378     if (fd >= 0)
379         close(fd);
380     free(filepath);
381     free(fpNew);
382     free(tbuffer);
383     return ret;
384 }
385
386 afs_int32
387 SBOZO_SetCellName(struct rx_call *acall, char *aname)
388 {
389     struct afsconf_cell tcell;
390     afs_int32 code;
391     char caller[MAXKTCNAMELEN];
392     char clones[MAXHOSTSPERCELL];
393
394     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
395         code = BZACCESS;
396         goto fail;
397     }
398     if (DoLogging)
399         bozo_Log("%s is executing SetCellName '%s'\n", caller, aname);
400
401     code =
402         afsconf_GetExtendedCellInfo(bozo_confdir, NULL, NULL, &tcell,
403                                     clones);
404     if (code)
405         goto fail;
406
407     /* Check that tcell has enough space for the new cellname. */
408     if (strlen(aname) > sizeof tcell.name - 1) {
409         bozo_Log
410             ("ERROR: SetCellName: cell name '%s' exceeds %ld bytes (cell name not changed)\n",
411              aname, (long)(sizeof tcell.name - 1));
412         code = BZDOM;
413         goto fail;
414     }
415
416     strcpy(tcell.name, aname);
417     code =
418         afsconf_SetExtendedCellInfo(bozo_confdir, AFSDIR_SERVER_ETC_DIRPATH,
419                                     &tcell, clones);
420
421   fail:
422     osi_auditU(acall, BOS_SetCellEvent, code, AUD_STR, aname, AUD_END);
423     return code;
424 }
425
426 afs_int32
427 SBOZO_GetCellName(struct rx_call *acall, char **aname)
428 {
429     afs_int32 code;
430     char tname[MAXCELLCHARS];
431
432     code = afsconf_GetLocalCell(bozo_confdir, tname, sizeof(tname));
433     if (code) {
434         /* must set output parameters even if aborting */
435         *aname = malloc(1);
436         **aname = 0;
437     } else {
438         *aname = strdup(tname);
439     }
440
441     return code;
442 }
443
444 afs_int32
445 SBOZO_GetCellHost(struct rx_call *acall, afs_uint32 awhich, char **aname)
446 {
447     afs_int32 code;
448     struct afsconf_cell tcell;
449     char *tp;
450     char clones[MAXHOSTSPERCELL];
451
452     code =
453         afsconf_GetExtendedCellInfo(bozo_confdir, NULL, NULL, &tcell,
454                                     clones);
455     if (code)
456         goto fail;
457
458     if (awhich >= tcell.numServers) {
459         code = BZDOM;
460         goto fail;
461     }
462
463     tp = tcell.hostName[awhich];
464     if (clones[awhich]) {
465         if (asprintf(aname, "[%s]", tp) < 0)
466             *aname = NULL;
467     } else
468         *aname = strdup(tp);
469     if (*aname == NULL) {
470         code = BZIO;
471         goto fail;
472     }
473     goto done;
474
475   fail:
476     *aname = malloc(1); /* return fake string */
477     **aname = 0;
478
479   done:
480     return code;
481 }
482
483 afs_int32
484 SBOZO_DeleteCellHost(struct rx_call *acall, char *aname)
485 {
486     afs_int32 code;
487     struct afsconf_cell tcell;
488     afs_int32 which;
489     int i;
490     char caller[MAXKTCNAMELEN];
491     char clones[MAXHOSTSPERCELL];
492
493     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
494         code = BZACCESS;
495         goto fail;
496     }
497     if (DoLogging)
498         bozo_Log("%s is executing DeleteCellHost '%s'\n", caller, aname);
499
500     code =
501         afsconf_GetExtendedCellInfo(bozo_confdir, NULL, NULL, &tcell,
502                                     clones);
503     if (code)
504         goto fail;
505
506     which = -1;
507     for (i = 0; i < tcell.numServers; i++) {
508         if (strcmp(tcell.hostName[i], aname) == 0) {
509             which = i;
510             break;
511         }
512     }
513
514     if (which < 0) {
515         code = BZNOENT;
516         goto fail;
517     }
518
519     memset(&tcell.hostAddr[which], 0, sizeof(struct sockaddr_in));
520     memset(tcell.hostName[which], 0, MAXHOSTCHARS);
521     code =
522         afsconf_SetExtendedCellInfo(bozo_confdir, AFSDIR_SERVER_ETC_DIRPATH,
523                                     &tcell, clones);
524
525   fail:
526     osi_auditU(acall, BOS_DeleteHostEvent, code, AUD_STR, aname, AUD_END);
527     return code;
528 }
529
530 afs_int32
531 SBOZO_AddCellHost(struct rx_call *acall, char *aname)
532 {
533     afs_int32 code;
534     struct afsconf_cell tcell;
535     afs_int32 which;
536     int i;
537     char caller[MAXKTCNAMELEN];
538     char clones[MAXHOSTSPERCELL];
539     char *n;
540     char isClone = 0;
541
542     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
543         code = BZACCESS;
544         goto fail;
545     }
546     if (DoLogging)
547         bozo_Log("%s is executing AddCellHost '%s'\n", caller, aname);
548
549     code =
550         afsconf_GetExtendedCellInfo(bozo_confdir, NULL, NULL, &tcell,
551                                     clones);
552     if (code)
553         goto fail;
554
555     n = aname;
556     if (*n == '[') {
557         *(n + strlen(n) - 1) = 0;
558         ++n;
559         isClone = 1;
560     }
561
562     which = -1;
563     for (i = 0; i < tcell.numServers; i++) {
564         if (strcmp(tcell.hostName[i], n) == 0) {
565             which = i;
566             break;
567         }
568     }
569     if (which < 0) {
570         which = tcell.numServers;
571         tcell.numServers++;
572
573         /*
574          * Check that tcell has enough space for an additional host.
575          *
576          * We assume that tcell.hostAddr[] and tcell.hostName[] have the
577          * same number of entries.
578          */
579         if (tcell.numServers >
580             sizeof tcell.hostAddr / sizeof tcell.hostAddr[0]) {
581             bozo_Log
582                 ("ERROR: AddCellHost: attempt to add more than %ld database servers (database server '%s' not added)\n",
583                  (long)(sizeof tcell.hostAddr / sizeof tcell.hostAddr[0]),
584                  aname);
585             code = BZDOM;
586             goto fail;
587         }
588
589         /* Check that tcell has enough space for the new hostname. */
590         if (strlen(aname) > sizeof tcell.hostName[0] - 1) {
591             bozo_Log
592                 ("ERROR: AddCellHost: host name '%s' exceeds %ld bytes (not added)\n",
593                  aname, (long)(sizeof tcell.hostName[0] - 1));
594             code = BZDOM;
595             goto fail;
596         }
597     }
598
599     memset(&tcell.hostAddr[which], 0, sizeof(struct sockaddr_in));
600     strcpy(tcell.hostName[which], n);
601     clones[which] = isClone;
602     code =
603         afsconf_SetExtendedCellInfo(bozo_confdir, AFSDIR_SERVER_ETC_DIRPATH,
604                                     &tcell, clones);
605
606   fail:
607     osi_auditU(acall, BOS_AddHostEvent, code, AUD_STR, aname, AUD_END);
608     return code;
609 }
610
611 afs_int32
612 SBOZO_ListKeys(struct rx_call *acall, afs_int32 an, afs_int32 *akvno,
613                struct bozo_key *akey, struct bozo_keyInfo *akeyinfo)
614 {
615     struct afsconf_keys tkeys;
616     afs_int32 code;
617     struct stat tstat;
618     int noauth = 0;
619     char caller[MAXKTCNAMELEN];
620     rxkad_level enc_level = rxkad_clear;
621
622     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
623         code = BZACCESS;
624         goto fail;
625     }
626     if (DoLogging)
627         bozo_Log("%s is executing ListKeys\n", caller);
628
629     code = afsconf_GetKeys(bozo_confdir, &tkeys);
630     if (code)
631         goto fail;
632
633     if (tkeys.nkeys <= an) {
634         code = BZDOM;
635         goto fail;
636     }
637     *akvno = tkeys.key[an].kvno;
638     memset(akeyinfo, 0, sizeof(struct bozo_keyInfo));
639
640     noauth = afsconf_GetNoAuthFlag(bozo_confdir);
641     rxkad_GetServerInfo(rx_ConnectionOf(acall), &enc_level, 0, 0, 0, 0, 0);
642     /*
643      * only return actual keys in noauth or if this is an encrypted connection
644      */
645
646     if ((noauth) || (enc_level == rxkad_crypt)) {
647         memcpy(akey, tkeys.key[an].key, 8);
648     } else
649         memset(akey, 0, 8);
650
651     code = stat(AFSDIR_SERVER_KEY_FILEPATH, &tstat);
652     if (code == 0) {
653         akeyinfo->mod_sec = tstat.st_mtime;
654     }
655
656     /* This will return an error if the key is 'bad' (bad checksum, weak DES
657      * key, etc). But we don't care, since we can still return the other
658      * information about the key, so ignore the result. */
659     (void)ka_KeyCheckSum(tkeys.key[an].key, &akeyinfo->keyCheckSum);
660
661   fail:
662     if (noauth)
663         osi_auditU(acall, BOS_UnAuthListKeysEvent, code, AUD_END);
664     osi_auditU(acall, BOS_ListKeysEvent, code, AUD_END);
665     return code;
666 }
667
668 afs_int32
669 SBOZO_AddKey(struct rx_call *acall, afs_int32 an, struct bozo_key *akey)
670 {
671     afs_int32 code;
672     char caller[MAXKTCNAMELEN];
673     rxkad_level enc_level = rxkad_clear;
674     int noauth;
675
676     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
677         code = BZACCESS;
678         goto fail;
679     }
680     noauth = afsconf_GetNoAuthFlag(bozo_confdir);
681     rxkad_GetServerInfo(rx_ConnectionOf(acall), &enc_level, 0, 0, 0, 0, 0);
682     if ((!noauth) && (enc_level != rxkad_crypt)) {
683         code = BZENCREQ;
684         goto fail;
685     }
686     if (DoLogging)
687         bozo_Log("%s is executing AddKey\n", caller);
688
689     code = afsconf_AddKey(bozo_confdir, an, akey->data, 0);
690     if (code == AFSCONF_KEYINUSE)
691         code = BZKEYINUSE;      /* Unique code for afs rpc calls */
692   fail:
693     osi_auditU(acall, BOS_AddKeyEvent, code, AUD_END);
694     return code;
695 }
696
697 afs_int32
698 SBOZO_SetNoAuthFlag(struct rx_call *acall, afs_int32 aflag)
699 {
700     afs_int32 code = 0;
701     char caller[MAXKTCNAMELEN];
702
703     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
704         code = BZACCESS;
705         goto fail;
706     }
707     if (DoLogging)
708         bozo_Log("%s is executing Set No Authentication\n", caller);
709
710     afsconf_SetNoAuthFlag(bozo_confdir, aflag);
711
712   fail:
713     osi_auditU(acall, BOS_SetNoAuthEvent, code, AUD_LONG, aflag, AUD_END);
714     return code;
715 }
716
717 afs_int32
718 SBOZO_DeleteKey(struct rx_call *acall, afs_int32 an)
719 {
720     afs_int32 code;
721     char caller[MAXKTCNAMELEN];
722
723     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
724         code = BZACCESS;
725         goto fail;
726     }
727     if (DoLogging)
728         bozo_Log("%s is executing DeleteKey\n", caller);
729
730     code = afsconf_DeleteKey(bozo_confdir, an);
731
732   fail:
733     osi_auditU(acall, BOS_DeleteKeyEvent, code, AUD_END);
734     return code;
735 }
736
737
738 afs_int32
739 SBOZO_ListSUsers(struct rx_call *acall, afs_int32 an, char **aname)
740 {
741     afs_int32 code;
742     char *tp;
743
744     tp = *aname = malloc(256);
745     *tp = 0;                    /* in case getnthuser doesn't null-terminate the string */
746     code = afsconf_GetNthUser(bozo_confdir, an, tp, 256);
747
748   /* fail: */
749     osi_auditU(acall, BOS_ListSUserEvent, code, AUD_END);
750     return code;
751 }
752
753 afs_int32
754 SBOZO_AddSUser(struct rx_call *acall, char *aname)
755 {
756     afs_int32 code;
757     char caller[MAXKTCNAMELEN];
758
759     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
760         code = BZACCESS;
761         goto fail;
762     }
763     if (DoLogging)
764         bozo_Log("%s is executing Add SuperUser '%s'\n", caller, aname);
765
766     code = afsconf_AddUser(bozo_confdir, aname);
767
768   fail:
769     osi_auditU(acall, BOS_AddSUserEvent, code, AUD_END);
770     return code;
771 }
772
773 afs_int32
774 SBOZO_DeleteSUser(struct rx_call *acall, char *aname)
775 {
776     afs_int32 code;
777     char caller[MAXKTCNAMELEN];
778
779     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
780         code = BZACCESS;
781         goto fail;
782     }
783
784     if (DoLogging)
785         bozo_Log("%s is executing Delete SuperUser '%s'\n", caller, aname);
786
787     code = afsconf_DeleteUser(bozo_confdir, aname);
788
789   fail:
790     osi_auditU(acall, BOS_DeleteSUserEvent, code, AUD_END);
791     return code;
792 }
793
794 afs_int32
795 SBOZO_CreateBnode(struct rx_call *acall, char *atype, char *ainstance,
796                   char *ap1, char *ap2, char *ap3, char *ap4, char *ap5,
797                   char *notifier)
798 {
799     struct bnode *tb;
800     afs_int32 code;
801     char caller[MAXKTCNAMELEN];
802
803     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
804         code = BZACCESS;
805         goto fail;
806     }
807     if (bozo_isrestricted) {
808         const char *salvpath = AFSDIR_CANONICAL_SERVER_SALVAGER_FILEPATH;
809         /* for DAFS, 'bos salvage' will pass "salvageserver -client" instead */
810         const char *salsrvpath = AFSDIR_CANONICAL_SERVER_SALSRV_FILEPATH " -client ";
811
812         /* still allow 'bos salvage' to work */
813         if (strcmp(atype, "cron") || strcmp(ainstance, "salvage-tmp")
814             || strcmp(ap2, "now")
815             || (strncmp(ap1, salvpath, strlen(salvpath))
816                 && strncmp(ap1, salsrvpath, strlen(salsrvpath)))) {
817
818             code = BZACCESS;
819             goto fail;
820         }
821     }
822
823     code =
824         bnode_Create(atype, ainstance, &tb, ap1, ap2, ap3, ap4, ap5, notifier,
825                      BSTAT_NORMAL, 1);
826     if (!code)
827         bnode_SetStat(tb, BSTAT_NORMAL);
828
829   fail:
830     osi_auditU(acall, BOS_CreateBnodeEvent, code, AUD_END);
831     return code;
832 }
833
834 afs_int32
835 SBOZO_WaitAll(struct rx_call *acall)
836 {
837     afs_int32 code;
838     char caller[MAXKTCNAMELEN];
839
840     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
841         code = BZACCESS;
842         goto fail;
843     }
844
845     if (DoLogging)
846         bozo_Log("%s is executing Wait for All\n", caller);
847
848     code = bnode_WaitAll();
849
850   fail:
851     osi_auditU(acall, BOS_WaitAllEvent, code, AUD_END);
852     return code;
853 }
854
855 afs_int32
856 SBOZO_DeleteBnode(struct rx_call *acall, char *ainstance)
857 {
858     afs_int32 code;
859     char caller[MAXKTCNAMELEN];
860
861     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
862         code = BZACCESS;
863         goto fail;
864     }
865     if (bozo_isrestricted) {
866         code = BZACCESS;
867         goto fail;
868     }
869     if (DoLogging)
870         bozo_Log("%s is executing DeleteBnode '%s'\n", caller, ainstance);
871
872     code = bnode_DeleteName(ainstance);
873
874   fail:
875     osi_auditU(acall, BOS_DeleteBnodeEvent, code, AUD_STR, ainstance,
876                AUD_END);
877     return code;
878 }
879
880 static int
881 swproc(struct bnode *abnode, void *arock)
882 {
883     if (abnode->goal == BSTAT_NORMAL)
884         return 0;               /* this one's not shutting down */
885     /* otherwise, we are shutting down */
886     bnode_Hold(abnode);
887     bnode_WaitStatus(abnode, BSTAT_SHUTDOWN);
888     bnode_Release(abnode);
889     return 0;                   /* don't stop apply function early, no matter what */
890 }
891
892 static int
893 stproc(struct bnode *abnode, void *arock)
894 {
895     if (abnode->fileGoal == BSTAT_SHUTDOWN)
896         return 0;               /* don't do these guys */
897
898     bnode_Hold(abnode);
899     bnode_ResetErrorCount(abnode);
900     bnode_SetStat(abnode, BSTAT_NORMAL);
901     bnode_Release(abnode);
902     return 0;
903 }
904
905 static int
906 sdproc(struct bnode *abnode, void *arock)
907 {
908     bnode_Hold(abnode);
909     bnode_SetStat(abnode, BSTAT_SHUTDOWN);
910     bnode_Release(abnode);
911     return 0;
912 }
913
914 /* shutdown and leave down */
915 afs_int32
916 SBOZO_ShutdownAll(struct rx_call *acall)
917 {
918     /* iterate over all bnodes, setting the status to temporarily disabled */
919     afs_int32 code;
920     char caller[MAXKTCNAMELEN];
921
922     /* check for authorization */
923     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
924         code = BZACCESS;
925         goto fail;
926     }
927     if (DoLogging)
928         bozo_Log("%s is executing ShutdownAll\n", caller);
929
930     code = bnode_ApplyInstance(sdproc, NULL);
931
932   fail:
933     osi_auditU(acall, BOS_ShutdownAllEvent, code, AUD_END);
934     return code;
935 }
936
937 /* shutdown and restart */
938 afs_int32
939 SBOZO_RestartAll(struct rx_call *acall)
940 {
941     afs_int32 code;
942     char caller[MAXKTCNAMELEN];
943
944     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
945         code = BZACCESS;
946         goto fail;
947     }
948     if (DoLogging)
949         bozo_Log("%s is executing RestartAll\n", caller);
950
951     /* start shutdown of all processes */
952     code = bnode_ApplyInstance(sdproc, NULL);
953     if (code)
954         goto fail;
955
956     /* wait for all done */
957     code = bnode_ApplyInstance(swproc, NULL);
958     if (code)
959         goto fail;
960
961     /* start them up again */
962     code = bnode_ApplyInstance(stproc, NULL);
963
964   fail:
965     osi_auditU(acall, BOS_RestartAllEvent, code, AUD_END);
966     return code;
967 }
968
969 afs_int32
970 SBOZO_ReBozo(struct rx_call *acall)
971 {
972     afs_int32 code;
973     char caller[MAXKTCNAMELEN];
974
975     /* acall is null if called internally to restart bosserver */
976     if (acall && !afsconf_SuperUser(bozo_confdir, acall, caller)) {
977         code = BZACCESS;
978         goto fail;
979     }
980     if (DoLogging)
981         bozo_Log("%s is executing ReBozo\n", caller);
982
983     /* start shutdown of all processes */
984     code = bnode_ApplyInstance(sdproc, NULL);
985     if (code)
986         goto fail;
987
988     /* wait for all done */
989     code = bnode_ApplyInstance(swproc, NULL);
990     if (code)
991         goto fail;
992
993     if (acall)
994         osi_auditU(acall, BOS_RebozoEvent, code, AUD_END);
995     else
996         osi_audit(BOS_RebozoIntEvent, code, AUD_END);
997
998     if (acall)
999         rx_EndCall(acall, 0);   /* try to get it done */
1000     rx_Finalize();
1001     bozo_ReBozo();              /* this reexecs us, and doesn't return, of course */
1002
1003   fail:
1004     /* Differentiate between external and internal ReBozo; prevents AFS_Aud_NoCall event */
1005     if (acall)
1006         osi_auditU(acall, BOS_RebozoEvent, code, AUD_END);
1007     else
1008         osi_audit(BOS_RebozoIntEvent, code, AUD_END);
1009     return code;                /* should only get here in unusual circumstances */
1010 }
1011
1012 /* make sure all are running */
1013 afs_int32
1014 SBOZO_StartupAll(struct rx_call *acall)
1015 {
1016     afs_int32 code;
1017     char caller[MAXKTCNAMELEN];
1018
1019     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
1020         code = BZACCESS;
1021         goto fail;
1022     }
1023     if (DoLogging)
1024         bozo_Log("%s is executing StartupAll\n", caller);
1025     code = bnode_ApplyInstance(stproc, NULL);
1026
1027   fail:
1028     osi_auditU(acall, BOS_StartupAllEvent, code, AUD_END);
1029     return code;
1030 }
1031
1032 afs_int32
1033 SBOZO_Restart(struct rx_call *acall, char *ainstance)
1034 {
1035     struct bnode *tb;
1036     afs_int32 code;
1037     char caller[MAXKTCNAMELEN];
1038
1039     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
1040         code = BZACCESS;
1041         goto fail;
1042     }
1043     if (DoLogging)
1044         bozo_Log("%s is executing Restart '%s'\n", caller, ainstance);
1045
1046     tb = bnode_FindInstance(ainstance);
1047     if (!tb) {
1048         code = BZNOENT;
1049         goto fail;
1050     }
1051
1052     bnode_Hold(tb);
1053     bnode_SetStat(tb, BSTAT_SHUTDOWN);
1054     code = bnode_WaitStatus(tb, BSTAT_SHUTDOWN);        /* this can fail */
1055     bnode_ResetErrorCount(tb);
1056     bnode_SetStat(tb, BSTAT_NORMAL);
1057     bnode_Release(tb);
1058
1059   fail:
1060     osi_auditU(acall, BOS_RestartEvent, code, AUD_STR, ainstance, AUD_END);
1061     return code;
1062 }
1063
1064 /* set temp status */
1065 afs_int32
1066 SBOZO_SetTStatus(struct rx_call *acall, char *ainstance, afs_int32 astatus)
1067 {
1068     struct bnode *tb;
1069     afs_int32 code;
1070     char caller[MAXKTCNAMELEN];
1071
1072     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
1073         code = BZACCESS;
1074         goto fail;
1075     }
1076     if (DoLogging)
1077         bozo_Log("%s is executing SetTempStatus '%s'\n", caller, ainstance);
1078
1079     tb = bnode_FindInstance(ainstance);
1080     if (!tb) {
1081         code = BZNOENT;
1082         goto fail;
1083     }
1084     bnode_Hold(tb);
1085     bnode_ResetErrorCount(tb);
1086     code = bnode_SetStat(tb, astatus);
1087     bnode_Release(tb);
1088
1089   fail:
1090     osi_auditU(acall, BOS_SetTempStatusEvent, code, AUD_STR, ainstance,
1091                AUD_END);
1092     return code;
1093 }
1094
1095 afs_int32
1096 SBOZO_SetStatus(struct rx_call *acall, char *ainstance, afs_int32 astatus)
1097 {
1098     struct bnode *tb;
1099     afs_int32 code;
1100     char caller[MAXKTCNAMELEN];
1101
1102     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
1103         code = BZACCESS;
1104         goto fail;
1105     }
1106     if (DoLogging)
1107         bozo_Log("%s is executing SetStatus '%s' (status = %d)\n", caller,
1108                  ainstance, astatus);
1109
1110     tb = bnode_FindInstance(ainstance);
1111     if (!tb) {
1112         code = BZNOENT;
1113         goto fail;
1114     }
1115     bnode_Hold(tb);
1116     bnode_SetFileGoal(tb, astatus);
1117     code = bnode_SetStat(tb, astatus);
1118     bnode_Release(tb);
1119
1120   fail:
1121     osi_auditU(acall, BOS_SetStatusEvent, code, AUD_STR, ainstance, AUD_END);
1122     return code;
1123 }
1124
1125 afs_int32
1126 SBOZO_GetStatus(struct rx_call *acall, char *ainstance, afs_int32 *astat,
1127                 char **astatDescr)
1128 {
1129     struct bnode *tb;
1130     afs_int32 code;
1131
1132     tb = bnode_FindInstance(ainstance);
1133     if (!tb) {
1134         code = BZNOENT;
1135         goto fail;
1136     }
1137
1138     bnode_Hold(tb);
1139     code = bnode_GetStat(tb, astat);
1140     if (code) {
1141         bnode_Release(tb);
1142         goto fail;
1143     }
1144
1145     *astatDescr = malloc(BOZO_BSSIZE);
1146     code = bnode_GetString(tb, *astatDescr, BOZO_BSSIZE);
1147     bnode_Release(tb);
1148     if (code)
1149         (*astatDescr)[0] = 0;   /* null string means no further info */
1150     return 0;
1151
1152   fail:
1153     *astatDescr = malloc(1);
1154     **astatDescr = 0;
1155     return code;
1156 }
1157
1158 struct eidata {
1159     char *iname;
1160     int counter;
1161 };
1162
1163 static int
1164 eifunc(struct bnode *abnode, void *param)
1165 {
1166     struct eidata *arock = (struct eidata *)param;
1167
1168     if (arock->counter-- == 0) {
1169         /* done */
1170         strcpy(arock->iname, abnode->name);
1171         return 1;
1172     } else {
1173         /* not there yet */
1174         return 0;
1175     }
1176 }
1177
1178 static int
1179 ZapFile(const char *adir, const char *aname)
1180 {
1181     char tbuffer[256];
1182     if (snprintf(tbuffer, 256, "%s/%s", adir, aname)<256)
1183         return unlink(tbuffer);
1184     else
1185         return -1;
1186 }
1187
1188 afs_int32
1189 SBOZO_Prune(struct rx_call *acall, afs_int32 aflags)
1190 {
1191     afs_int32 code;
1192     DIR *dirp;
1193     struct dirent *tde;
1194     int i;
1195     char caller[MAXKTCNAMELEN];
1196
1197     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
1198         code = BZACCESS;
1199         goto fail;
1200     }
1201     if (bozo_isrestricted) {
1202         code = BZACCESS;
1203         goto fail;
1204     }
1205     if (DoLogging)
1206         bozo_Log("%s is executing Prune (flags=%d)\n", caller, aflags);
1207
1208     /* first scan AFS binary directory */
1209     dirp = opendir(AFSDIR_SERVER_BIN_DIRPATH);
1210     if (dirp) {
1211         for (tde = readdir(dirp); tde; tde = readdir(dirp)) {
1212             i = strlen(tde->d_name);
1213             if (aflags & BOZO_PRUNEOLD) {
1214                 if (i >= 4 && strncmp(tde->d_name + i - 4, ".OLD", 4) == 0)
1215                     ZapFile(AFSDIR_SERVER_BIN_DIRPATH, tde->d_name);
1216             }
1217             if (aflags & BOZO_PRUNEBAK) {
1218                 if (i >= 4 && strncmp(tde->d_name + i - 4, ".BAK", 4) == 0)
1219                     ZapFile(AFSDIR_SERVER_BIN_DIRPATH, tde->d_name);
1220             }
1221         }
1222         closedir(dirp);
1223     }
1224
1225     /* then scan AFS log directory */
1226     dirp = opendir(AFSDIR_SERVER_LOGS_DIRPATH);
1227     if (dirp) {
1228         for (tde = readdir(dirp); tde; tde = readdir(dirp)) {
1229             if (aflags & BOZO_PRUNECORE) {
1230                 if (strncmp(tde->d_name, AFSDIR_CORE_FILE, 4) == 0)
1231                     ZapFile(AFSDIR_SERVER_LOGS_DIRPATH, tde->d_name);
1232             }
1233         }
1234         closedir(dirp);
1235     }
1236     code = 0;
1237
1238   fail:
1239     osi_auditU(acall, BOS_PruneLogs, code, AUD_END);
1240     return code;
1241 }
1242
1243 afs_int32
1244 SBOZO_EnumerateInstance(struct rx_call *acall, afs_int32 anum,
1245                         char **ainstance)
1246 {
1247     struct eidata tdata;
1248
1249     *ainstance = malloc(BOZO_BSSIZE);
1250     **ainstance = 0;
1251     tdata.counter = anum;
1252     tdata.iname = *ainstance;
1253     bnode_ApplyInstance(eifunc, &tdata);
1254     if (tdata.counter >= 0)
1255         return BZDOM;           /* anum > # of actual instances */
1256     else
1257         return 0;
1258 }
1259
1260 struct bozo_bosEntryStats bozo_bosEntryStats[] = {
1261     {NULL, 1, 1, 0755, 02},     /* AFSDIR_SERVER_AFS_DIRPATH    */
1262     {NULL, 1, 1, 0755, 02},     /* AFSDIR_SERVER_ETC_DIRPATH    */
1263     {NULL, 1, 1, 0755, 02},     /* AFSDIR_SERVER_BIN_DIRPATH    */
1264     {NULL, 1, 1, 0755, 02},     /* AFSDIR_SERVER_LOGS_DIRPATH   */
1265     {NULL, 1, 0, 0700, 07},     /* AFSDIR_SERVER_BACKUP_DIRPATH */
1266     {NULL, 1, 1, 0700, 07},     /* AFSDIR_SERVER_DB_DIRPATH     */
1267     {NULL, 1, 1, 0700, 07},     /* AFSDIR_SERVER_LOCAL_DIRPATH  */
1268     {NULL, 0, 1, 0600, 07},     /* AFSDIR_SERVER_KEY_FILEPATH   */
1269     {NULL, 0, 1, 0600, 03},     /* AFSDIR_SERVER_ULIST_FILEPATH */
1270     {NULL, 0, 1, 0600, 07},     /* AFSDIR_SERVER_RXKAD_KEYTAB_FILEPATH   */
1271     {NULL, 0, 1, 0600, 07}      /* AFSDIR_SERVER_EXT_KEY_FILEPATH   */
1272 };
1273 int bozo_nbosEntryStats =
1274     sizeof(bozo_bosEntryStats) / sizeof(bozo_bosEntryStats[0]);
1275
1276 /* This function performs initialization of the bozo_bosEntrystats[]
1277  * array. This array contains the list of dirs that the bosserver
1278  * is interested in along with their recommended permissions
1279  * NOTE: This initialization is a bit ugly. This was caused because
1280  * the path names require procedural as opposed to static initialization.
1281  * The other fields in the struct are however, statically initialized.
1282  */
1283 int
1284 initBosEntryStats(void)
1285 {
1286     bozo_bosEntryStats[0].path = AFSDIR_SERVER_AFS_DIRPATH;
1287     bozo_bosEntryStats[1].path = AFSDIR_SERVER_ETC_DIRPATH;
1288     bozo_bosEntryStats[2].path = AFSDIR_SERVER_BIN_DIRPATH;
1289     bozo_bosEntryStats[3].path = AFSDIR_SERVER_LOGS_DIRPATH;
1290     bozo_bosEntryStats[4].path = AFSDIR_SERVER_BACKUP_DIRPATH;
1291     bozo_bosEntryStats[5].path = AFSDIR_SERVER_DB_DIRPATH;
1292     bozo_bosEntryStats[6].path = AFSDIR_SERVER_LOCAL_DIRPATH;
1293     bozo_bosEntryStats[7].path = AFSDIR_SERVER_KEY_FILEPATH;
1294     bozo_bosEntryStats[8].path = AFSDIR_SERVER_ULIST_FILEPATH;
1295     bozo_bosEntryStats[9].path = AFSDIR_SERVER_RXKAD_KEYTAB_FILEPATH;
1296     bozo_bosEntryStats[10].path = AFSDIR_SERVER_EXT_KEY_FILEPATH;
1297
1298     return 0;
1299 }
1300
1301 /* StatEachEntry - If it's not there, it is okay.  If anything else goes wrong
1302  * complain.  Otherwise check permissions: shouldn't allow write or (usually)
1303  * read. */
1304
1305 static int
1306 StatEachEntry(IN struct bozo_bosEntryStats *stats)
1307 {
1308     struct stat info;
1309     if (stat(stats->path, &info)) {
1310         if (errno == ENOENT)
1311             return 1;           /* no such entry: just ignore it */
1312         return 0;               /* something else went wrong */
1313     } else {
1314         int rights;
1315         if (((info.st_mode & S_IFDIR) != 0) != stats->dir)
1316             return 0;           /* not expected type */
1317         if (stats->rootOwner && (info.st_uid != 0))
1318             return 0;           /* not owned by root */
1319         rights = (info.st_mode & 0000777);
1320         if ((rights & stats->reqPerm) != stats->reqPerm)
1321             return 0;           /* required permissions not present */
1322         if ((rights & stats->proPerm) != 0)
1323             return 0;           /* prohibited permissions present */
1324     }
1325     return 1;
1326 }
1327
1328 /* DirAccessOK - checks the mode bits on the AFS dir and decendents and
1329  * returns 0 if some are not OK and 1 otherwise.  For efficiency, it doesn't do
1330  * this check more often than every 5 seconds. */
1331
1332 int
1333 DirAccessOK(void)
1334 {
1335 #ifdef AFS_NT40_ENV
1336     /* underlying filesystem may not support directory protection */
1337     return 1;
1338 #else
1339     static afs_uint32 lastTime = 0;
1340     afs_uint32 now = FT_ApproxTime();
1341     static int lastResult = -1;
1342     int result;
1343     int i;
1344
1345     if ((now - lastTime) < 5)
1346         return lastResult;
1347     lastTime = now;
1348
1349     result = 1;
1350     for (i = 0; i < bozo_nbosEntryStats; i++) {
1351         struct bozo_bosEntryStats *e = &bozo_bosEntryStats[i];
1352         if (!StatEachEntry(e)) {
1353             bozo_Log("unhappy with %s which is a %s that should "
1354                      "have at least rights %o, at most rights %o %s\n",
1355                      e->path, e->dir ? "dir" : "file", e->reqPerm,
1356                      (~e->proPerm & 0777),
1357                      e->rootOwner ? ", owned by root" : "");
1358             result = 0;
1359             break;
1360         }
1361     }
1362
1363     if (result != lastResult) { /* log changes */
1364         bozo_Log("Server directory access is %sokay\n",
1365                  (result ? "" : "not "));
1366     }
1367     lastResult = result;
1368     return lastResult;
1369 #endif /* AFS_NT40_ENV */
1370 }
1371
1372 int
1373 GetRequiredDirPerm(const char *path)
1374 {
1375     int i;
1376     for (i = 0; i < bozo_nbosEntryStats; i++)
1377         if (strcmp(path, bozo_bosEntryStats[i].path) == 0)
1378             return bozo_bosEntryStats[i].reqPerm;
1379     return -1;
1380 }
1381
1382 afs_int32
1383 SBOZO_GetInstanceInfo(IN struct rx_call *acall,
1384                       IN char *ainstance,
1385                       OUT char **atype,
1386                       OUT struct bozo_status *astatus)
1387 {
1388     struct bnode *tb;
1389
1390     tb = bnode_FindInstance(ainstance);
1391     *atype = malloc(BOZO_BSSIZE);
1392     **atype = 0;
1393     if (!tb)
1394         return BZNOENT;
1395     if (tb->type)
1396         strcpy(*atype, tb->type->name);
1397     else
1398         (*atype)[0] = 0;        /* null string */
1399     memset(astatus, 0, sizeof(struct bozo_status));     /* good defaults */
1400     astatus->goal = tb->goal;
1401     astatus->fileGoal = tb->fileGoal;
1402     astatus->procStartTime = tb->procStartTime;
1403     astatus->procStarts = tb->procStarts;
1404     astatus->lastAnyExit = tb->lastAnyExit;
1405     astatus->lastErrorExit = tb->lastErrorExit;
1406     astatus->errorCode = tb->errorCode;
1407     astatus->errorSignal = tb->errorSignal;
1408     if (tb->flags & BNODE_ERRORSTOP)
1409         astatus->flags |= BOZO_ERRORSTOP;
1410     if (bnode_HasCore(tb))
1411         astatus->flags |= BOZO_HASCORE;
1412     if (!DirAccessOK())
1413         astatus->flags |= BOZO_BADDIRACCESS;
1414     return 0;
1415 }
1416
1417 afs_int32
1418 SBOZO_GetInstanceParm(struct rx_call *acall,
1419                       char *ainstance,
1420                       afs_int32 anum,
1421                       char **aparm)
1422 {
1423     struct bnode *tb;
1424     char *tp;
1425     afs_int32 code;
1426
1427     tp = malloc(BOZO_BSSIZE);
1428     *aparm = tp;
1429     *tp = 0;                    /* null-terminate string in error case */
1430     tb = bnode_FindInstance(ainstance);
1431     if (!tb)
1432         return BZNOENT;
1433     bnode_Hold(tb);
1434     if (anum == 999) {
1435         if (tb->notifier) {
1436             memcpy(tp, tb->notifier, strlen(tb->notifier) + 1);
1437             code = 0;
1438         } else
1439             code = BZNOENT;     /* XXXXX */
1440     } else
1441         code = bnode_GetParm(tb, anum, tp, BOZO_BSSIZE);
1442     bnode_Release(tb);
1443
1444     /* Not Currently Audited */
1445     return code;
1446 }
1447
1448 afs_int32
1449 SBOZO_GetLog(struct rx_call *acall, char *aname)
1450 {
1451     afs_int32 code;
1452     FILE *tfile;
1453     int tc;
1454     char *logpath;
1455     char buffer;
1456     char caller[MAXKTCNAMELEN];
1457
1458     /* Check access since 'aname' could specify a file outside of the
1459      * AFS log directory (which is bosserver's working directory).
1460      */
1461     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
1462         code = BZACCESS;
1463         goto fail;
1464     }
1465     if (bozo_isrestricted && strchr(aname, '/')
1466         && strcmp(aname, AFSDIR_CANONICAL_SERVER_SLVGLOG_FILEPATH)) {
1467         code = BZACCESS;
1468         goto fail;
1469     }
1470
1471     /* construct local path from canonical (wire-format) path */
1472     if (ConstructLocalLogPath(aname, &logpath)) {
1473         return BZNOENT;
1474     }
1475     if (DoLogging)
1476         bozo_Log("%s is executing GetLog '%s'\n", caller, logpath);
1477     tfile = fopen(logpath, "r");
1478     free(logpath);
1479
1480     if (!tfile) {
1481         return BZNOENT;
1482     }
1483
1484     while (1) {
1485         tc = getc(tfile);
1486         if (tc == 0)
1487             continue;           /* our termination condition on other end */
1488         if (tc == EOF)
1489             break;
1490         buffer = tc;
1491         if (rx_Write(acall, &buffer, 1) != 1) {
1492             fclose(tfile);
1493             code = BZNET;
1494             goto fail;
1495         }
1496     }
1497
1498     /* all done, cleanup and return */
1499     fclose(tfile);
1500
1501     /* write out the end delimeter */
1502     buffer = 0;
1503     if (rx_Write(acall, &buffer, 1) != 1)
1504         return BZNET;
1505     code = 0;
1506
1507   fail:
1508     osi_auditU(acall, BOS_GetLogsEvent, code, AUD_END);
1509     return code;
1510 }
1511
1512 afs_int32
1513 SBOZO_GetInstanceStrings(struct rx_call *acall, char *abnodeName,
1514                          char **as1, char **as2, char **as3, char **as4)
1515 {
1516     struct bnode *tb;
1517
1518     *as2 = malloc(1);
1519     **as2 = 0;
1520     *as3 = malloc(1);
1521     **as3 = 0;
1522     *as4 = malloc(1);
1523     **as4 = 0;
1524     tb = bnode_FindInstance(abnodeName);
1525     if (!tb)
1526         goto fail;
1527
1528     /* now, return the appropriate error string, if any */
1529     if (tb->lastErrorName) {
1530         *as1 = strdup(tb->lastErrorName);
1531     } else {
1532         *as1 = malloc(1);
1533         **as1 = 0;
1534     }
1535     return 0;
1536
1537   fail:
1538     *as1 = malloc(1);
1539     **as1 = 0;
1540     return BZNOENT;
1541 }
1542
1543 afs_int32
1544 SBOZO_GetRestrictedMode(struct rx_call *acall, afs_int32 *arestmode)
1545 {
1546     *arestmode = bozo_isrestricted;
1547     return 0;
1548 }
1549
1550 afs_int32
1551 SBOZO_SetRestrictedMode(struct rx_call *acall, afs_int32 arestmode)
1552 {
1553     afs_int32 code;
1554     char caller[MAXKTCNAMELEN];
1555
1556     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
1557         return BZACCESS;
1558     }
1559     if (bozo_isrestricted) {
1560         return BZACCESS;
1561     }
1562     if (arestmode != 0 && arestmode != 1) {
1563         return BZDOM;
1564     }
1565     bozo_isrestricted = arestmode;
1566     code = WriteBozoFile(0);
1567
1568     return code;
1569 }
1570
1571 void *
1572 bozo_ShutdownAndExit(void *param)
1573 {
1574     int asignal = (intptr_t)param;
1575     int code;
1576
1577     bozo_Log
1578         ("Shutdown of BOS server and processes in response to signal %d\n",
1579          asignal);
1580
1581     /* start shutdown of all processes */
1582     if ((code = bnode_ApplyInstance(sdproc, NULL)) == 0) {
1583         /* wait for shutdown to complete */
1584         code = bnode_ApplyInstance(swproc, NULL);
1585     }
1586
1587     if (code) {
1588         bozo_Log("Shutdown incomplete (code = %d); manual cleanup required\n",
1589                  code);
1590     }
1591
1592     rx_Finalize();
1593     exit(code);
1594 }