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