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