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