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