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