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