2b799814e8e39af34b71193d696f294c64d241d5
[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 = BZIO;
310         fpNew = NULL;
311         goto out;
312     }
313     tbuffer = malloc(AFSDIR_PATH_MAX);
314     if (tbuffer == NULL) {
315         ret = BZIO;
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 == 0) {
434         *aname = strdup(tname);
435         if (*aname == NULL)
436             code = BZIO;
437     }
438
439     return code;
440 }
441
442 afs_int32
443 SBOZO_GetCellHost(struct rx_call *acall, afs_uint32 awhich, char **aname)
444 {
445     afs_int32 code;
446     struct afsconf_cell tcell;
447     char *tp;
448     char clones[MAXHOSTSPERCELL];
449
450     code =
451         afsconf_GetExtendedCellInfo(bozo_confdir, NULL, NULL, &tcell,
452                                     clones);
453     if (code)
454         goto fail;
455
456     if (awhich >= tcell.numServers) {
457         code = BZDOM;
458         goto fail;
459     }
460
461     tp = tcell.hostName[awhich];
462     if (clones[awhich]) {
463         if (asprintf(aname, "[%s]", tp) < 0)
464             *aname = NULL;
465     } else
466         *aname = strdup(tp);
467     if (*aname == NULL) {
468         code = BZIO;
469         goto fail;
470     }
471     goto done;
472
473   fail:
474     *aname = malloc(1); /* return fake string */
475     **aname = 0;
476
477   done:
478     return code;
479 }
480
481 afs_int32
482 SBOZO_DeleteCellHost(struct rx_call *acall, char *aname)
483 {
484     afs_int32 code;
485     struct afsconf_cell tcell;
486     afs_int32 which;
487     int i;
488     char caller[MAXKTCNAMELEN];
489     char clones[MAXHOSTSPERCELL];
490
491     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
492         code = BZACCESS;
493         goto fail;
494     }
495     if (DoLogging)
496         bozo_Log("%s is executing DeleteCellHost '%s'\n", caller, aname);
497
498     code =
499         afsconf_GetExtendedCellInfo(bozo_confdir, NULL, NULL, &tcell,
500                                     clones);
501     if (code)
502         goto fail;
503
504     which = -1;
505     for (i = 0; i < tcell.numServers; i++) {
506         if (strcmp(tcell.hostName[i], aname) == 0) {
507             which = i;
508             break;
509         }
510     }
511
512     if (which < 0) {
513         code = BZNOENT;
514         goto fail;
515     }
516
517     memset(&tcell.hostAddr[which], 0, sizeof(struct sockaddr_in));
518     memset(tcell.hostName[which], 0, MAXHOSTCHARS);
519     code =
520         afsconf_SetExtendedCellInfo(bozo_confdir, AFSDIR_SERVER_ETC_DIRPATH,
521                                     &tcell, clones);
522
523   fail:
524     osi_auditU(acall, BOS_DeleteHostEvent, code, AUD_STR, aname, AUD_END);
525     return code;
526 }
527
528 afs_int32
529 SBOZO_AddCellHost(struct rx_call *acall, char *aname)
530 {
531     afs_int32 code;
532     struct afsconf_cell tcell;
533     afs_int32 which;
534     int i;
535     char caller[MAXKTCNAMELEN];
536     char clones[MAXHOSTSPERCELL];
537     char *n;
538     char isClone = 0;
539
540     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
541         code = BZACCESS;
542         goto fail;
543     }
544     if (DoLogging)
545         bozo_Log("%s is executing AddCellHost '%s'\n", caller, aname);
546
547     code =
548         afsconf_GetExtendedCellInfo(bozo_confdir, NULL, NULL, &tcell,
549                                     clones);
550     if (code)
551         goto fail;
552
553     n = aname;
554     if (*n == '[') {
555         *(n + strlen(n) - 1) = 0;
556         ++n;
557         isClone = 1;
558     }
559
560     which = -1;
561     for (i = 0; i < tcell.numServers; i++) {
562         if (strcmp(tcell.hostName[i], n) == 0) {
563             which = i;
564             break;
565         }
566     }
567     if (which < 0) {
568         which = tcell.numServers;
569         tcell.numServers++;
570
571         /*
572          * Check that tcell has enough space for an additional host.
573          *
574          * We assume that tcell.hostAddr[] and tcell.hostName[] have the
575          * same number of entries.
576          */
577         if (tcell.numServers >
578             sizeof tcell.hostAddr / sizeof tcell.hostAddr[0]) {
579             bozo_Log
580                 ("ERROR: AddCellHost: attempt to add more than %ld database servers (database server '%s' not added)\n",
581                  (long)(sizeof tcell.hostAddr / sizeof tcell.hostAddr[0]),
582                  aname);
583             code = BZDOM;
584             goto fail;
585         }
586
587         /* Check that tcell has enough space for the new hostname. */
588         if (strlen(aname) > sizeof tcell.hostName[0] - 1) {
589             bozo_Log
590                 ("ERROR: AddCellHost: host name '%s' exceeds %ld bytes (not added)\n",
591                  aname, (long)(sizeof tcell.hostName[0] - 1));
592             code = BZDOM;
593             goto fail;
594         }
595     }
596
597     memset(&tcell.hostAddr[which], 0, sizeof(struct sockaddr_in));
598     strcpy(tcell.hostName[which], n);
599     clones[which] = isClone;
600     code =
601         afsconf_SetExtendedCellInfo(bozo_confdir, AFSDIR_SERVER_ETC_DIRPATH,
602                                     &tcell, clones);
603
604   fail:
605     osi_auditU(acall, BOS_AddHostEvent, code, AUD_STR, aname, AUD_END);
606     return code;
607 }
608
609 afs_int32
610 SBOZO_ListKeys(struct rx_call *acall, afs_int32 an, afs_int32 *akvno,
611                struct bozo_key *akey, struct bozo_keyInfo *akeyinfo)
612 {
613     struct afsconf_keys tkeys;
614     afs_int32 code;
615     struct stat tstat;
616     int noauth = 0;
617     char caller[MAXKTCNAMELEN];
618     rxkad_level enc_level = rxkad_clear;
619
620     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
621         code = BZACCESS;
622         goto fail;
623     }
624     if (DoLogging)
625         bozo_Log("%s is executing ListKeys\n", caller);
626
627     code = afsconf_GetKeys(bozo_confdir, &tkeys);
628     if (code)
629         goto fail;
630
631     if (tkeys.nkeys <= an) {
632         code = BZDOM;
633         goto fail;
634     }
635     *akvno = tkeys.key[an].kvno;
636     memset(akeyinfo, 0, sizeof(struct bozo_keyInfo));
637
638     noauth = afsconf_GetNoAuthFlag(bozo_confdir);
639     rxkad_GetServerInfo(rx_ConnectionOf(acall), &enc_level, 0, 0, 0, 0, 0);
640     /*
641      * only return actual keys in noauth or if this is an encrypted connection
642      */
643
644     if ((noauth) || (enc_level == rxkad_crypt)) {
645         memcpy(akey, tkeys.key[an].key, 8);
646     } else
647         memset(akey, 0, 8);
648
649     code = stat(AFSDIR_SERVER_KEY_FILEPATH, &tstat);
650     if (code == 0) {
651         akeyinfo->mod_sec = tstat.st_mtime;
652     }
653
654     /* This will return an error if the key is 'bad' (bad checksum, weak DES
655      * key, etc). But we don't care, since we can still return the other
656      * information about the key, so ignore the result. */
657     (void)ka_KeyCheckSum(tkeys.key[an].key, &akeyinfo->keyCheckSum);
658
659   fail:
660     if (noauth)
661         osi_auditU(acall, BOS_UnAuthListKeysEvent, code, AUD_END);
662     osi_auditU(acall, BOS_ListKeysEvent, code, AUD_END);
663     return code;
664 }
665
666 afs_int32
667 SBOZO_AddKey(struct rx_call *acall, afs_int32 an, struct bozo_key *akey)
668 {
669     afs_int32 code;
670     char caller[MAXKTCNAMELEN];
671     rxkad_level enc_level = rxkad_clear;
672     int noauth;
673
674     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
675         code = BZACCESS;
676         goto fail;
677     }
678     noauth = afsconf_GetNoAuthFlag(bozo_confdir);
679     rxkad_GetServerInfo(rx_ConnectionOf(acall), &enc_level, 0, 0, 0, 0, 0);
680     if ((!noauth) && (enc_level != rxkad_crypt)) {
681         code = BZENCREQ;
682         goto fail;
683     }
684     if (DoLogging)
685         bozo_Log("%s is executing AddKey\n", caller);
686
687     code = afsconf_AddKey(bozo_confdir, an, akey->data, 0);
688     if (code == AFSCONF_KEYINUSE)
689         code = BZKEYINUSE;      /* Unique code for afs rpc calls */
690   fail:
691     osi_auditU(acall, BOS_AddKeyEvent, code, AUD_END);
692     return code;
693 }
694
695 afs_int32
696 SBOZO_SetNoAuthFlag(struct rx_call *acall, afs_int32 aflag)
697 {
698     afs_int32 code = 0;
699     char caller[MAXKTCNAMELEN];
700
701     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
702         code = BZACCESS;
703         goto fail;
704     }
705     if (DoLogging)
706         bozo_Log("%s is executing Set No Authentication\n", caller);
707
708     afsconf_SetNoAuthFlag(bozo_confdir, aflag);
709
710   fail:
711     osi_auditU(acall, BOS_SetNoAuthEvent, code, AUD_LONG, aflag, AUD_END);
712     return code;
713 }
714
715 afs_int32
716 SBOZO_DeleteKey(struct rx_call *acall, afs_int32 an)
717 {
718     afs_int32 code;
719     char caller[MAXKTCNAMELEN];
720
721     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
722         code = BZACCESS;
723         goto fail;
724     }
725     if (DoLogging)
726         bozo_Log("%s is executing DeleteKey\n", caller);
727
728     code = afsconf_DeleteKey(bozo_confdir, an);
729
730   fail:
731     osi_auditU(acall, BOS_DeleteKeyEvent, code, AUD_END);
732     return code;
733 }
734
735
736 afs_int32
737 SBOZO_ListSUsers(struct rx_call *acall, afs_int32 an, char **aname)
738 {
739     afs_int32 code;
740     char *tp;
741
742     tp = *aname = malloc(256);
743     *tp = 0;                    /* in case getnthuser doesn't null-terminate the string */
744     code = afsconf_GetNthUser(bozo_confdir, an, tp, 256);
745
746   /* fail: */
747     osi_auditU(acall, BOS_ListSUserEvent, code, AUD_END);
748     return code;
749 }
750
751 afs_int32
752 SBOZO_AddSUser(struct rx_call *acall, char *aname)
753 {
754     afs_int32 code;
755     char caller[MAXKTCNAMELEN];
756
757     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
758         code = BZACCESS;
759         goto fail;
760     }
761     if (DoLogging)
762         bozo_Log("%s is executing Add SuperUser '%s'\n", caller, aname);
763
764     code = afsconf_AddUser(bozo_confdir, aname);
765
766   fail:
767     osi_auditU(acall, BOS_AddSUserEvent, code, AUD_END);
768     return code;
769 }
770
771 afs_int32
772 SBOZO_DeleteSUser(struct rx_call *acall, char *aname)
773 {
774     afs_int32 code;
775     char caller[MAXKTCNAMELEN];
776
777     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
778         code = BZACCESS;
779         goto fail;
780     }
781
782     if (DoLogging)
783         bozo_Log("%s is executing Delete SuperUser '%s'\n", caller, aname);
784
785     code = afsconf_DeleteUser(bozo_confdir, aname);
786
787   fail:
788     osi_auditU(acall, BOS_DeleteSUserEvent, code, AUD_END);
789     return code;
790 }
791
792 afs_int32
793 SBOZO_CreateBnode(struct rx_call *acall, char *atype, char *ainstance,
794                   char *ap1, char *ap2, char *ap3, char *ap4, char *ap5,
795                   char *notifier)
796 {
797     struct bnode *tb;
798     afs_int32 code;
799     char caller[MAXKTCNAMELEN];
800
801     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
802         code = BZACCESS;
803         goto fail;
804     }
805     if (bozo_isrestricted) {
806         const char *salvpath = AFSDIR_CANONICAL_SERVER_SALVAGER_FILEPATH;
807         /* for DAFS, 'bos salvage' will pass "salvageserver -client" instead */
808         const char *salsrvpath = AFSDIR_CANONICAL_SERVER_SALSRV_FILEPATH " -client ";
809
810         /* still allow 'bos salvage' to work */
811         if (strcmp(atype, "cron") || strcmp(ainstance, "salvage-tmp")
812             || strcmp(ap2, "now")
813             || (strncmp(ap1, salvpath, strlen(salvpath))
814                 && strncmp(ap1, salsrvpath, strlen(salsrvpath)))) {
815
816             code = BZACCESS;
817             goto fail;
818         }
819     }
820
821     code =
822         bnode_Create(atype, ainstance, &tb, ap1, ap2, ap3, ap4, ap5, notifier,
823                      BSTAT_NORMAL, 1);
824     if (!code)
825         bnode_SetStat(tb, BSTAT_NORMAL);
826
827   fail:
828     osi_auditU(acall, BOS_CreateBnodeEvent, code, AUD_END);
829     return code;
830 }
831
832 afs_int32
833 SBOZO_WaitAll(struct rx_call *acall)
834 {
835     afs_int32 code;
836     char caller[MAXKTCNAMELEN];
837
838     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
839         code = BZACCESS;
840         goto fail;
841     }
842
843     if (DoLogging)
844         bozo_Log("%s is executing Wait for All\n", caller);
845
846     code = bnode_WaitAll();
847
848   fail:
849     osi_auditU(acall, BOS_WaitAllEvent, code, AUD_END);
850     return code;
851 }
852
853 afs_int32
854 SBOZO_DeleteBnode(struct rx_call *acall, char *ainstance)
855 {
856     afs_int32 code;
857     char caller[MAXKTCNAMELEN];
858
859     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
860         code = BZACCESS;
861         goto fail;
862     }
863     if (bozo_isrestricted) {
864         code = BZACCESS;
865         goto fail;
866     }
867     if (DoLogging)
868         bozo_Log("%s is executing DeleteBnode '%s'\n", caller, ainstance);
869
870     code = bnode_DeleteName(ainstance);
871
872   fail:
873     osi_auditU(acall, BOS_DeleteBnodeEvent, code, AUD_STR, ainstance,
874                AUD_END);
875     return code;
876 }
877
878 static int
879 swproc(struct bnode *abnode, void *arock)
880 {
881     if (abnode->goal == BSTAT_NORMAL)
882         return 0;               /* this one's not shutting down */
883     /* otherwise, we are shutting down */
884     bnode_Hold(abnode);
885     bnode_WaitStatus(abnode, BSTAT_SHUTDOWN);
886     bnode_Release(abnode);
887     return 0;                   /* don't stop apply function early, no matter what */
888 }
889
890 static int
891 stproc(struct bnode *abnode, void *arock)
892 {
893     if (abnode->fileGoal == BSTAT_SHUTDOWN)
894         return 0;               /* don't do these guys */
895
896     bnode_Hold(abnode);
897     bnode_ResetErrorCount(abnode);
898     bnode_SetStat(abnode, BSTAT_NORMAL);
899     bnode_Release(abnode);
900     return 0;
901 }
902
903 static int
904 sdproc(struct bnode *abnode, void *arock)
905 {
906     bnode_Hold(abnode);
907     bnode_SetStat(abnode, BSTAT_SHUTDOWN);
908     bnode_Release(abnode);
909     return 0;
910 }
911
912 /* shutdown and leave down */
913 afs_int32
914 SBOZO_ShutdownAll(struct rx_call *acall)
915 {
916     /* iterate over all bnodes, setting the status to temporarily disabled */
917     afs_int32 code;
918     char caller[MAXKTCNAMELEN];
919
920     /* check for authorization */
921     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
922         code = BZACCESS;
923         goto fail;
924     }
925     if (DoLogging)
926         bozo_Log("%s is executing ShutdownAll\n", caller);
927
928     code = bnode_ApplyInstance(sdproc, NULL);
929
930   fail:
931     osi_auditU(acall, BOS_ShutdownAllEvent, code, AUD_END);
932     return code;
933 }
934
935 /* shutdown and restart */
936 afs_int32
937 SBOZO_RestartAll(struct rx_call *acall)
938 {
939     afs_int32 code;
940     char caller[MAXKTCNAMELEN];
941
942     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
943         code = BZACCESS;
944         goto fail;
945     }
946     if (DoLogging)
947         bozo_Log("%s is executing RestartAll\n", caller);
948
949     /* start shutdown of all processes */
950     code = bnode_ApplyInstance(sdproc, NULL);
951     if (code)
952         goto fail;
953
954     /* wait for all done */
955     code = bnode_ApplyInstance(swproc, NULL);
956     if (code)
957         goto fail;
958
959     /* start them up again */
960     code = bnode_ApplyInstance(stproc, NULL);
961
962   fail:
963     osi_auditU(acall, BOS_RestartAllEvent, code, AUD_END);
964     return code;
965 }
966
967 afs_int32
968 SBOZO_ReBozo(struct rx_call *acall)
969 {
970     afs_int32 code;
971     char caller[MAXKTCNAMELEN];
972
973     /* acall is null if called internally to restart bosserver */
974     if (acall && !afsconf_SuperUser(bozo_confdir, acall, caller)) {
975         code = BZACCESS;
976         goto fail;
977     }
978     if (DoLogging)
979         bozo_Log("%s is executing ReBozo\n", caller);
980
981     /* start shutdown of all processes */
982     code = bnode_ApplyInstance(sdproc, NULL);
983     if (code)
984         goto fail;
985
986     /* wait for all done */
987     code = bnode_ApplyInstance(swproc, NULL);
988     if (code)
989         goto fail;
990
991     if (acall)
992         osi_auditU(acall, BOS_RebozoEvent, code, AUD_END);
993     else
994         osi_audit(BOS_RebozoIntEvent, code, AUD_END);
995
996     if (acall)
997         rx_EndCall(acall, 0);   /* try to get it done */
998     rx_Finalize();
999     bozo_ReBozo();              /* this reexecs us, and doesn't return, of course */
1000
1001   fail:
1002     /* Differentiate between external and internal ReBozo; prevents AFS_Aud_NoCall event */
1003     if (acall)
1004         osi_auditU(acall, BOS_RebozoEvent, code, AUD_END);
1005     else
1006         osi_audit(BOS_RebozoIntEvent, code, AUD_END);
1007     return code;                /* should only get here in unusual circumstances */
1008 }
1009
1010 /* make sure all are running */
1011 afs_int32
1012 SBOZO_StartupAll(struct rx_call *acall)
1013 {
1014     afs_int32 code;
1015     char caller[MAXKTCNAMELEN];
1016
1017     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
1018         code = BZACCESS;
1019         goto fail;
1020     }
1021     if (DoLogging)
1022         bozo_Log("%s is executing StartupAll\n", caller);
1023     code = bnode_ApplyInstance(stproc, NULL);
1024
1025   fail:
1026     osi_auditU(acall, BOS_StartupAllEvent, code, AUD_END);
1027     return code;
1028 }
1029
1030 afs_int32
1031 SBOZO_Restart(struct rx_call *acall, char *ainstance)
1032 {
1033     struct bnode *tb;
1034     afs_int32 code;
1035     char caller[MAXKTCNAMELEN];
1036
1037     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
1038         code = BZACCESS;
1039         goto fail;
1040     }
1041     if (DoLogging)
1042         bozo_Log("%s is executing Restart '%s'\n", caller, ainstance);
1043
1044     tb = bnode_FindInstance(ainstance);
1045     if (!tb) {
1046         code = BZNOENT;
1047         goto fail;
1048     }
1049
1050     bnode_Hold(tb);
1051     bnode_SetStat(tb, BSTAT_SHUTDOWN);
1052     code = bnode_WaitStatus(tb, BSTAT_SHUTDOWN);        /* this can fail */
1053     bnode_ResetErrorCount(tb);
1054     bnode_SetStat(tb, BSTAT_NORMAL);
1055     bnode_Release(tb);
1056
1057   fail:
1058     osi_auditU(acall, BOS_RestartEvent, code, AUD_STR, ainstance, AUD_END);
1059     return code;
1060 }
1061
1062 /* set temp status */
1063 afs_int32
1064 SBOZO_SetTStatus(struct rx_call *acall, char *ainstance, afs_int32 astatus)
1065 {
1066     struct bnode *tb;
1067     afs_int32 code;
1068     char caller[MAXKTCNAMELEN];
1069
1070     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
1071         code = BZACCESS;
1072         goto fail;
1073     }
1074     if (DoLogging)
1075         bozo_Log("%s is executing SetTempStatus '%s'\n", caller, ainstance);
1076
1077     tb = bnode_FindInstance(ainstance);
1078     if (!tb) {
1079         code = BZNOENT;
1080         goto fail;
1081     }
1082     bnode_Hold(tb);
1083     bnode_ResetErrorCount(tb);
1084     code = bnode_SetStat(tb, astatus);
1085     bnode_Release(tb);
1086
1087   fail:
1088     osi_auditU(acall, BOS_SetTempStatusEvent, code, AUD_STR, ainstance,
1089                AUD_END);
1090     return code;
1091 }
1092
1093 afs_int32
1094 SBOZO_SetStatus(struct rx_call *acall, char *ainstance, afs_int32 astatus)
1095 {
1096     struct bnode *tb;
1097     afs_int32 code;
1098     char caller[MAXKTCNAMELEN];
1099
1100     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
1101         code = BZACCESS;
1102         goto fail;
1103     }
1104     if (DoLogging)
1105         bozo_Log("%s is executing SetStatus '%s' (status = %d)\n", caller,
1106                  ainstance, astatus);
1107
1108     tb = bnode_FindInstance(ainstance);
1109     if (!tb) {
1110         code = BZNOENT;
1111         goto fail;
1112     }
1113     bnode_Hold(tb);
1114     bnode_SetFileGoal(tb, astatus);
1115     code = bnode_SetStat(tb, astatus);
1116     bnode_Release(tb);
1117
1118   fail:
1119     osi_auditU(acall, BOS_SetStatusEvent, code, AUD_STR, ainstance, AUD_END);
1120     return code;
1121 }
1122
1123 afs_int32
1124 SBOZO_GetStatus(struct rx_call *acall, char *ainstance, afs_int32 *astat,
1125                 char **astatDescr)
1126 {
1127     struct bnode *tb;
1128     afs_int32 code;
1129
1130     tb = bnode_FindInstance(ainstance);
1131     if (!tb) {
1132         code = BZNOENT;
1133         goto fail;
1134     }
1135
1136     bnode_Hold(tb);
1137     code = bnode_GetStat(tb, astat);
1138     if (code) {
1139         bnode_Release(tb);
1140         goto fail;
1141     }
1142
1143     *astatDescr = malloc(BOZO_BSSIZE);
1144     code = bnode_GetString(tb, *astatDescr, BOZO_BSSIZE);
1145     bnode_Release(tb);
1146     if (code)
1147         (*astatDescr)[0] = 0;   /* null string means no further info */
1148     return 0;
1149
1150   fail:
1151     *astatDescr = malloc(1);
1152     **astatDescr = 0;
1153     return code;
1154 }
1155
1156 struct eidata {
1157     char *iname;
1158     int counter;
1159 };
1160
1161 static int
1162 eifunc(struct bnode *abnode, void *param)
1163 {
1164     struct eidata *arock = (struct eidata *)param;
1165
1166     if (arock->counter-- == 0) {
1167         /* done */
1168         strcpy(arock->iname, abnode->name);
1169         return 1;
1170     } else {
1171         /* not there yet */
1172         return 0;
1173     }
1174 }
1175
1176 static int
1177 ZapFile(const char *adir, const char *aname)
1178 {
1179     char tbuffer[256];
1180     if (snprintf(tbuffer, 256, "%s/%s", adir, aname)<256)
1181         return unlink(tbuffer);
1182     else
1183         return -1;
1184 }
1185
1186 afs_int32
1187 SBOZO_Prune(struct rx_call *acall, afs_int32 aflags)
1188 {
1189     afs_int32 code;
1190     DIR *dirp;
1191     struct dirent *tde;
1192     int i;
1193     char caller[MAXKTCNAMELEN];
1194
1195     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
1196         code = BZACCESS;
1197         goto fail;
1198     }
1199     if (bozo_isrestricted) {
1200         code = BZACCESS;
1201         goto fail;
1202     }
1203     if (DoLogging)
1204         bozo_Log("%s is executing Prune (flags=%d)\n", caller, aflags);
1205
1206     /* first scan AFS binary directory */
1207     dirp = opendir(AFSDIR_SERVER_BIN_DIRPATH);
1208     if (dirp) {
1209         for (tde = readdir(dirp); tde; tde = readdir(dirp)) {
1210             i = strlen(tde->d_name);
1211             if (aflags & BOZO_PRUNEOLD) {
1212                 if (i >= 4 && strncmp(tde->d_name + i - 4, ".OLD", 4) == 0)
1213                     ZapFile(AFSDIR_SERVER_BIN_DIRPATH, tde->d_name);
1214             }
1215             if (aflags & BOZO_PRUNEBAK) {
1216                 if (i >= 4 && strncmp(tde->d_name + i - 4, ".BAK", 4) == 0)
1217                     ZapFile(AFSDIR_SERVER_BIN_DIRPATH, tde->d_name);
1218             }
1219         }
1220         closedir(dirp);
1221     }
1222
1223     /* then scan AFS log directory */
1224     dirp = opendir(AFSDIR_SERVER_LOGS_DIRPATH);
1225     if (dirp) {
1226         for (tde = readdir(dirp); tde; tde = readdir(dirp)) {
1227             if (aflags & BOZO_PRUNECORE) {
1228                 if (strncmp(tde->d_name, AFSDIR_CORE_FILE, 4) == 0)
1229                     ZapFile(AFSDIR_SERVER_LOGS_DIRPATH, tde->d_name);
1230             }
1231         }
1232         closedir(dirp);
1233     }
1234     code = 0;
1235
1236   fail:
1237     osi_auditU(acall, BOS_PruneLogs, code, AUD_END);
1238     return code;
1239 }
1240
1241 afs_int32
1242 SBOZO_EnumerateInstance(struct rx_call *acall, afs_int32 anum,
1243                         char **ainstance)
1244 {
1245     struct eidata tdata;
1246
1247     if (anum < 0)
1248         return BZDOM;
1249
1250     *ainstance = malloc(BOZO_BSSIZE);
1251     **ainstance = 0;
1252     tdata.counter = anum;
1253     tdata.iname = *ainstance;
1254     bnode_ApplyInstance(eifunc, &tdata);
1255     if (tdata.counter >= 0)
1256         return BZDOM;           /* anum > # of actual instances */
1257     else
1258         return 0;
1259 }
1260
1261 struct bozo_bosEntryStats bozo_bosEntryStats[] = {
1262     {NULL, 1, 1, 0755, 02},     /* AFSDIR_SERVER_AFS_DIRPATH    */
1263     {NULL, 1, 1, 0755, 02},     /* AFSDIR_SERVER_ETC_DIRPATH    */
1264     {NULL, 1, 1, 0755, 02},     /* AFSDIR_SERVER_BIN_DIRPATH    */
1265     {NULL, 1, 1, 0755, 02},     /* AFSDIR_SERVER_LOGS_DIRPATH   */
1266     {NULL, 1, 0, 0700, 07},     /* AFSDIR_SERVER_BACKUP_DIRPATH */
1267     {NULL, 1, 1, 0700, 07},     /* AFSDIR_SERVER_DB_DIRPATH     */
1268     {NULL, 1, 1, 0700, 07},     /* AFSDIR_SERVER_LOCAL_DIRPATH  */
1269     {NULL, 0, 1, 0600, 07},     /* AFSDIR_SERVER_KEY_FILEPATH   */
1270     {NULL, 0, 1, 0600, 03},     /* AFSDIR_SERVER_ULIST_FILEPATH */
1271     {NULL, 0, 1, 0600, 07},     /* AFSDIR_SERVER_RXKAD_KEYTAB_FILEPATH   */
1272     {NULL, 0, 1, 0600, 07}      /* AFSDIR_SERVER_EXT_KEY_FILEPATH   */
1273 };
1274 int bozo_nbosEntryStats =
1275     sizeof(bozo_bosEntryStats) / sizeof(bozo_bosEntryStats[0]);
1276
1277 /* This function performs initialization of the bozo_bosEntrystats[]
1278  * array. This array contains the list of dirs that the bosserver
1279  * is interested in along with their recommended permissions
1280  * NOTE: This initialization is a bit ugly. This was caused because
1281  * the path names require procedural as opposed to static initialization.
1282  * The other fields in the struct are however, statically initialized.
1283  */
1284 int
1285 initBosEntryStats(void)
1286 {
1287     bozo_bosEntryStats[0].path = AFSDIR_SERVER_AFS_DIRPATH;
1288     bozo_bosEntryStats[1].path = AFSDIR_SERVER_ETC_DIRPATH;
1289     bozo_bosEntryStats[2].path = AFSDIR_SERVER_BIN_DIRPATH;
1290     bozo_bosEntryStats[3].path = AFSDIR_SERVER_LOGS_DIRPATH;
1291     bozo_bosEntryStats[4].path = AFSDIR_SERVER_BACKUP_DIRPATH;
1292     bozo_bosEntryStats[5].path = AFSDIR_SERVER_DB_DIRPATH;
1293     bozo_bosEntryStats[6].path = AFSDIR_SERVER_LOCAL_DIRPATH;
1294     bozo_bosEntryStats[7].path = AFSDIR_SERVER_KEY_FILEPATH;
1295     bozo_bosEntryStats[8].path = AFSDIR_SERVER_ULIST_FILEPATH;
1296     bozo_bosEntryStats[9].path = AFSDIR_SERVER_RXKAD_KEYTAB_FILEPATH;
1297     bozo_bosEntryStats[10].path = AFSDIR_SERVER_EXT_KEY_FILEPATH;
1298
1299     return 0;
1300 }
1301
1302 /* StatEachEntry - If it's not there, it is okay.  If anything else goes wrong
1303  * complain.  Otherwise check permissions: shouldn't allow write or (usually)
1304  * read. */
1305
1306 static int
1307 StatEachEntry(IN struct bozo_bosEntryStats *stats)
1308 {
1309     struct stat info;
1310     if (stat(stats->path, &info)) {
1311         if (errno == ENOENT)
1312             return 1;           /* no such entry: just ignore it */
1313         return 0;               /* something else went wrong */
1314     } else {
1315         int rights;
1316         if (((info.st_mode & S_IFDIR) != 0) != stats->dir)
1317             return 0;           /* not expected type */
1318         if (stats->rootOwner && (info.st_uid != 0))
1319             return 0;           /* not owned by root */
1320         rights = (info.st_mode & 0000777);
1321         if ((rights & stats->reqPerm) != stats->reqPerm)
1322             return 0;           /* required permissions not present */
1323         if ((rights & stats->proPerm) != 0)
1324             return 0;           /* prohibited permissions present */
1325     }
1326     return 1;
1327 }
1328
1329 /* DirAccessOK - checks the mode bits on the AFS dir and decendents and
1330  * returns 0 if some are not OK and 1 otherwise.  For efficiency, it doesn't do
1331  * this check more often than every 5 seconds. */
1332
1333 int
1334 DirAccessOK(void)
1335 {
1336 #ifdef AFS_NT40_ENV
1337     /* underlying filesystem may not support directory protection */
1338     return 1;
1339 #else
1340     static afs_uint32 lastTime = 0;
1341     afs_uint32 now = FT_ApproxTime();
1342     static int lastResult = -1;
1343     int result;
1344     int i;
1345
1346     if ((now - lastTime) < 5)
1347         return lastResult;
1348     lastTime = now;
1349
1350     result = 1;
1351     for (i = 0; i < bozo_nbosEntryStats; i++) {
1352         struct bozo_bosEntryStats *e = &bozo_bosEntryStats[i];
1353         if (!StatEachEntry(e)) {
1354             bozo_Log("unhappy with %s which is a %s that should "
1355                      "have at least rights %o, at most rights %o %s\n",
1356                      e->path, e->dir ? "dir" : "file", e->reqPerm,
1357                      (~e->proPerm & 0777),
1358                      e->rootOwner ? ", owned by root" : "");
1359             result = 0;
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 }