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