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