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