4510660923801a71def10e5668980606f639149b
[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 = (char *)malloc(strlen(tname) + 1);
403         strcpy(*aname, 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     *aname = (char *)malloc(strlen(tp) + 3);
430     if (clones[awhich]) {
431         strcpy(*aname, "[");
432         strcat(*aname, tp);
433         strcat(*aname, "]");
434     } else
435         strcpy(*aname, tp);
436     goto done;
437
438   fail:
439     *aname = (char *)malloc(1); /* return fake string */
440     **aname = 0;
441
442   done:
443     return code;
444 }
445
446 afs_int32
447 SBOZO_DeleteCellHost(struct rx_call *acall, char *aname)
448 {
449     afs_int32 code;
450     struct afsconf_cell tcell;
451     afs_int32 which;
452     int i;
453     char caller[MAXKTCNAMELEN];
454     char clones[MAXHOSTSPERCELL];
455
456     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
457         code = BZACCESS;
458         goto fail;
459     }
460     if (DoLogging)
461         bozo_Log("%s is executing DeleteCellHost '%s'\n", caller, aname);
462
463     code =
464         afsconf_GetExtendedCellInfo(bozo_confdir, NULL, NULL, &tcell,
465                                     clones);
466     if (code)
467         goto fail;
468
469     which = -1;
470     for (i = 0; i < tcell.numServers; i++) {
471         if (strcmp(tcell.hostName[i], aname) == 0) {
472             which = i;
473             break;
474         }
475     }
476
477     if (which < 0) {
478         code = BZNOENT;
479         goto fail;
480     }
481
482     memset(&tcell.hostAddr[which], 0, sizeof(struct sockaddr_in));
483     memset(tcell.hostName[which], 0, MAXHOSTCHARS);
484     code =
485         afsconf_SetExtendedCellInfo(bozo_confdir, AFSDIR_SERVER_ETC_DIRPATH,
486                                     &tcell, clones);
487
488   fail:
489     osi_auditU(acall, BOS_DeleteHostEvent, code, AUD_STR, aname, AUD_END);
490     return code;
491 }
492
493 afs_int32
494 SBOZO_AddCellHost(struct rx_call *acall, char *aname)
495 {
496     afs_int32 code;
497     struct afsconf_cell tcell;
498     afs_int32 which;
499     int i;
500     char caller[MAXKTCNAMELEN];
501     char clones[MAXHOSTSPERCELL];
502     char *n;
503     char isClone = 0;
504
505     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
506         code = BZACCESS;
507         goto fail;
508     }
509     if (DoLogging)
510         bozo_Log("%s is executing AddCellHost '%s'\n", caller, aname);
511
512     code =
513         afsconf_GetExtendedCellInfo(bozo_confdir, NULL, NULL, &tcell,
514                                     clones);
515     if (code)
516         goto fail;
517
518     n = aname;
519     if (*n == '[') {
520         *(n + strlen(n) - 1) = 0;
521         ++n;
522         isClone = 1;
523     }
524
525     which = -1;
526     for (i = 0; i < tcell.numServers; i++) {
527         if (strcmp(tcell.hostName[i], n) == 0) {
528             which = i;
529             break;
530         }
531     }
532     if (which < 0) {
533         which = tcell.numServers;
534         tcell.numServers++;
535
536         /*
537          * Check that tcell has enough space for an additional host.
538          *
539          * We assume that tcell.hostAddr[] and tcell.hostName[] have the
540          * same number of entries.
541          */
542         if (tcell.numServers >
543             sizeof tcell.hostAddr / sizeof tcell.hostAddr[0]) {
544             bozo_Log
545                 ("ERROR: AddCellHost: attempt to add more than %ld database servers (database server '%s' not added)\n",
546                  (long)(sizeof tcell.hostAddr / sizeof tcell.hostAddr[0]),
547                  aname);
548             code = BZDOM;
549             goto fail;
550         }
551
552         /* Check that tcell has enough space for the new hostname. */
553         if (strlen(aname) > sizeof tcell.hostName[0] - 1) {
554             bozo_Log
555                 ("ERROR: AddCellHost: host name '%s' exceeds %ld bytes (not added)\n",
556                  aname, (long)(sizeof tcell.hostName[0] - 1));
557             code = BZDOM;
558             goto fail;
559         }
560     }
561
562     memset(&tcell.hostAddr[which], 0, sizeof(struct sockaddr_in));
563     strcpy(tcell.hostName[which], n);
564     clones[which] = isClone;
565     code =
566         afsconf_SetExtendedCellInfo(bozo_confdir, AFSDIR_SERVER_ETC_DIRPATH,
567                                     &tcell, clones);
568
569   fail:
570     osi_auditU(acall, BOS_AddHostEvent, code, AUD_STR, aname, AUD_END);
571     return code;
572 }
573
574 afs_int32
575 SBOZO_ListKeys(struct rx_call *acall, afs_int32 an, afs_int32 *akvno,
576                struct bozo_key *akey, struct bozo_keyInfo *akeyinfo)
577 {
578     struct afsconf_keys tkeys;
579     afs_int32 code;
580     struct stat tstat;
581     int noauth = 0;
582     char caller[MAXKTCNAMELEN];
583     rxkad_level enc_level = rxkad_clear;
584
585     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
586         code = BZACCESS;
587         goto fail;
588     }
589     if (DoLogging)
590         bozo_Log("%s is executing ListKeys\n", caller);
591
592     code = afsconf_GetKeys(bozo_confdir, &tkeys);
593     if (code)
594         goto fail;
595
596     if (tkeys.nkeys <= an) {
597         code = BZDOM;
598         goto fail;
599     }
600     *akvno = tkeys.key[an].kvno;
601     memset(akeyinfo, 0, sizeof(struct bozo_keyInfo));
602
603     noauth = afsconf_GetNoAuthFlag(bozo_confdir);
604     rxkad_GetServerInfo(rx_ConnectionOf(acall), &enc_level, 0, 0, 0, 0, 0);
605     /*
606      * only return actual keys in noauth or if this is an encrypted connection
607      */
608
609     if ((noauth) || (enc_level == rxkad_crypt)) {
610         memcpy(akey, tkeys.key[an].key, 8);
611     } else
612         memset(akey, 0, 8);
613
614     code = stat(AFSDIR_SERVER_KEY_FILEPATH, &tstat);
615     if (code == 0) {
616         akeyinfo->mod_sec = tstat.st_mtime;
617     }
618     ka_KeyCheckSum(tkeys.key[an].key, &akeyinfo->keyCheckSum);
619     /* only errors is bad key parity */
620
621   fail:
622     if (noauth)
623         osi_auditU(acall, BOS_UnAuthListKeysEvent, code, AUD_END);
624     osi_auditU(acall, BOS_ListKeysEvent, code, AUD_END);
625     return code;
626 }
627
628 afs_int32
629 SBOZO_AddKey(struct rx_call *acall, afs_int32 an, struct bozo_key *akey)
630 {
631     afs_int32 code;
632     char caller[MAXKTCNAMELEN];
633     rxkad_level enc_level = rxkad_clear;
634     int noauth;
635
636     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
637         code = BZACCESS;
638         goto fail;
639     }
640     noauth = afsconf_GetNoAuthFlag(bozo_confdir);
641     rxkad_GetServerInfo(rx_ConnectionOf(acall), &enc_level, 0, 0, 0, 0, 0);
642     if ((!noauth) && (enc_level != rxkad_crypt)) {
643         code = BZENCREQ;
644         goto fail;
645     }
646     if (DoLogging)
647         bozo_Log("%s is executing AddKey\n", caller);
648
649     code = afsconf_AddKey(bozo_confdir, an, akey->data, 0);
650     if (code == AFSCONF_KEYINUSE)
651         code = BZKEYINUSE;      /* Unique code for afs rpc calls */
652   fail:
653     osi_auditU(acall, BOS_AddKeyEvent, code, AUD_END);
654     return code;
655 }
656
657 afs_int32
658 SBOZO_SetNoAuthFlag(struct rx_call *acall, afs_int32 aflag)
659 {
660     afs_int32 code = 0;
661     char caller[MAXKTCNAMELEN];
662
663     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
664         code = BZACCESS;
665         goto fail;
666     }
667     if (DoLogging)
668         bozo_Log("%s is executing Set No Authentication\n", caller);
669
670     afsconf_SetNoAuthFlag(bozo_confdir, aflag);
671
672   fail:
673     osi_auditU(acall, BOS_SetNoAuthEvent, code, AUD_LONG, aflag, AUD_END);
674     return code;
675 }
676
677 afs_int32
678 SBOZO_DeleteKey(struct rx_call *acall, afs_int32 an)
679 {
680     afs_int32 code;
681     char caller[MAXKTCNAMELEN];
682
683     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
684         code = BZACCESS;
685         goto fail;
686     }
687     if (DoLogging)
688         bozo_Log("%s is executing DeleteKey\n", caller);
689
690     code = afsconf_DeleteKey(bozo_confdir, an);
691
692   fail:
693     osi_auditU(acall, BOS_DeleteKeyEvent, code, AUD_END);
694     return code;
695 }
696
697
698 afs_int32
699 SBOZO_ListSUsers(struct rx_call *acall, afs_int32 an, char **aname)
700 {
701     afs_int32 code;
702     char *tp;
703
704     tp = *aname = (char *)malloc(256);
705     *tp = 0;                    /* in case getnthuser doesn't null-terminate the string */
706     code = afsconf_GetNthUser(bozo_confdir, an, tp, 256);
707
708   /* fail: */
709     osi_auditU(acall, BOS_ListSUserEvent, code, AUD_END);
710     return code;
711 }
712
713 afs_int32
714 SBOZO_AddSUser(struct rx_call *acall, char *aname)
715 {
716     afs_int32 code;
717     char caller[MAXKTCNAMELEN];
718
719     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
720         code = BZACCESS;
721         goto fail;
722     }
723     if (DoLogging)
724         bozo_Log("%s is executing Add SuperUser '%s'\n", caller, aname);
725
726     code = afsconf_AddUser(bozo_confdir, aname);
727
728   fail:
729     osi_auditU(acall, BOS_AddSUserEvent, code, AUD_END);
730     return code;
731 }
732
733 afs_int32
734 SBOZO_DeleteSUser(struct rx_call *acall, char *aname)
735 {
736     afs_int32 code;
737     char caller[MAXKTCNAMELEN];
738
739     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
740         code = BZACCESS;
741         goto fail;
742     }
743
744     if (DoLogging)
745         bozo_Log("%s is executing Delete SuperUser '%s'\n", caller, aname);
746
747     code = afsconf_DeleteUser(bozo_confdir, aname);
748
749   fail:
750     osi_auditU(acall, BOS_DeleteSUserEvent, code, AUD_END);
751     return code;
752 }
753
754 afs_int32
755 SBOZO_CreateBnode(struct rx_call *acall, char *atype, char *ainstance,
756                   char *ap1, char *ap2, char *ap3, char *ap4, char *ap5,
757                   char *notifier)
758 {
759     struct bnode *tb;
760     afs_int32 code;
761     char caller[MAXKTCNAMELEN];
762
763     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
764         code = BZACCESS;
765         goto fail;
766     }
767     if (bozo_isrestricted) {
768         const char *salvpath = AFSDIR_CANONICAL_SERVER_SALVAGER_FILEPATH;
769         /* for DAFS, 'bos salvage' will pass "salvageserver -client" instead */
770         const char *salsrvpath = AFSDIR_CANONICAL_SERVER_SALSRV_FILEPATH " -client ";
771
772         /* still allow 'bos salvage' to work */
773         if (strcmp(atype, "cron") || strcmp(ainstance, "salvage-tmp")
774             || strcmp(ap2, "now")
775             || (strncmp(ap1, salvpath, strlen(salvpath))
776                 && strncmp(ap1, salsrvpath, strlen(salsrvpath)))) {
777
778             code = BZACCESS;
779             goto fail;
780         }
781     }
782
783     code =
784         bnode_Create(atype, ainstance, &tb, ap1, ap2, ap3, ap4, ap5, notifier,
785                      BSTAT_NORMAL, 1);
786     if (!code)
787         bnode_SetStat(tb, BSTAT_NORMAL);
788
789   fail:
790     osi_auditU(acall, BOS_CreateBnodeEvent, code, AUD_END);
791     return code;
792 }
793
794 afs_int32
795 SBOZO_WaitAll(struct rx_call *acall)
796 {
797     afs_int32 code;
798     char caller[MAXKTCNAMELEN];
799
800     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
801         code = BZACCESS;
802         goto fail;
803     }
804
805     if (DoLogging)
806         bozo_Log("%s is executing Wait for All\n", caller);
807
808     code = bnode_WaitAll();
809
810   fail:
811     osi_auditU(acall, BOS_WaitAllEvent, code, AUD_END);
812     return code;
813 }
814
815 afs_int32
816 SBOZO_DeleteBnode(struct rx_call *acall, char *ainstance)
817 {
818     afs_int32 code;
819     char caller[MAXKTCNAMELEN];
820
821     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
822         code = BZACCESS;
823         goto fail;
824     }
825     if (bozo_isrestricted) {
826         code = BZACCESS;
827         goto fail;
828     }
829     if (DoLogging)
830         bozo_Log("%s is executing DeleteBnode '%s'\n", caller, ainstance);
831
832     code = bnode_DeleteName(ainstance);
833
834   fail:
835     osi_auditU(acall, BOS_DeleteBnodeEvent, code, AUD_STR, ainstance,
836                AUD_END);
837     return code;
838 }
839
840 static int
841 swproc(struct bnode *abnode, void *arock)
842 {
843     if (abnode->goal == BSTAT_NORMAL)
844         return 0;               /* this one's not shutting down */
845     /* otherwise, we are shutting down */
846     bnode_Hold(abnode);
847     bnode_WaitStatus(abnode, BSTAT_SHUTDOWN);
848     bnode_Release(abnode);
849     return 0;                   /* don't stop apply function early, no matter what */
850 }
851
852 static int
853 stproc(struct bnode *abnode, void *arock)
854 {
855     if (abnode->fileGoal == BSTAT_SHUTDOWN)
856         return 0;               /* don't do these guys */
857
858     bnode_Hold(abnode);
859     bnode_ResetErrorCount(abnode);
860     bnode_SetStat(abnode, BSTAT_NORMAL);
861     bnode_Release(abnode);
862     return 0;
863 }
864
865 static int
866 sdproc(struct bnode *abnode, void *arock)
867 {
868     bnode_Hold(abnode);
869     bnode_SetStat(abnode, BSTAT_SHUTDOWN);
870     bnode_Release(abnode);
871     return 0;
872 }
873
874 /* shutdown and leave down */
875 afs_int32
876 SBOZO_ShutdownAll(struct rx_call *acall)
877 {
878     /* iterate over all bnodes, setting the status to temporarily disabled */
879     afs_int32 code;
880     char caller[MAXKTCNAMELEN];
881
882     /* check for authorization */
883     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
884         code = BZACCESS;
885         goto fail;
886     }
887     if (DoLogging)
888         bozo_Log("%s is executing ShutdownAll\n", caller);
889
890     code = bnode_ApplyInstance(sdproc, NULL);
891
892   fail:
893     osi_auditU(acall, BOS_ShutdownAllEvent, code, AUD_END);
894     return code;
895 }
896
897 /* shutdown and restart */
898 afs_int32
899 SBOZO_RestartAll(struct rx_call *acall)
900 {
901     afs_int32 code;
902     char caller[MAXKTCNAMELEN];
903
904     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
905         code = BZACCESS;
906         goto fail;
907     }
908     if (DoLogging)
909         bozo_Log("%s is executing RestartAll\n", caller);
910
911     /* start shutdown of all processes */
912     code = bnode_ApplyInstance(sdproc, NULL);
913     if (code)
914         goto fail;
915
916     /* wait for all done */
917     code = bnode_ApplyInstance(swproc, NULL);
918     if (code)
919         goto fail;
920
921     /* start them up again */
922     code = bnode_ApplyInstance(stproc, NULL);
923
924   fail:
925     osi_auditU(acall, BOS_RestartAllEvent, code, AUD_END);
926     return code;
927 }
928
929 afs_int32
930 SBOZO_ReBozo(struct rx_call *acall)
931 {
932     afs_int32 code;
933     char caller[MAXKTCNAMELEN];
934
935     /* acall is null if called internally to restart bosserver */
936     if (acall && !afsconf_SuperUser(bozo_confdir, acall, caller)) {
937         code = BZACCESS;
938         goto fail;
939     }
940     if (DoLogging)
941         bozo_Log("%s is executing ReBozo\n", caller);
942
943     /* start shutdown of all processes */
944     code = bnode_ApplyInstance(sdproc, NULL);
945     if (code)
946         goto fail;
947
948     /* wait for all done */
949     code = bnode_ApplyInstance(swproc, NULL);
950     if (code)
951         goto fail;
952
953     if (acall)
954         osi_auditU(acall, BOS_RebozoEvent, code, AUD_END);
955     else
956         osi_audit(BOS_RebozoIntEvent, code, AUD_END);
957
958     if (acall)
959         rx_EndCall(acall, 0);   /* try to get it done */
960     rx_Finalize();
961     bozo_ReBozo();              /* this reexecs us, and doesn't return, of course */
962
963   fail:
964     /* Differentiate between external and internal ReBozo; prevents AFS_Aud_NoCall event */
965     if (acall)
966         osi_auditU(acall, BOS_RebozoEvent, code, AUD_END);
967     else
968         osi_audit(BOS_RebozoIntEvent, code, AUD_END);
969     return code;                /* should only get here in unusual circumstances */
970 }
971
972 /* make sure all are running */
973 afs_int32
974 SBOZO_StartupAll(struct rx_call *acall)
975 {
976     afs_int32 code;
977     char caller[MAXKTCNAMELEN];
978
979     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
980         code = BZACCESS;
981         goto fail;
982     }
983     if (DoLogging)
984         bozo_Log("%s is executing StartupAll\n", caller);
985     code = bnode_ApplyInstance(stproc, NULL);
986
987   fail:
988     osi_auditU(acall, BOS_StartupAllEvent, code, AUD_END);
989     return code;
990 }
991
992 afs_int32
993 SBOZO_Restart(struct rx_call *acall, char *ainstance)
994 {
995     struct bnode *tb;
996     afs_int32 code;
997     char caller[MAXKTCNAMELEN];
998
999     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
1000         code = BZACCESS;
1001         goto fail;
1002     }
1003     if (DoLogging)
1004         bozo_Log("%s is executing Restart '%s'\n", caller, ainstance);
1005
1006     tb = bnode_FindInstance(ainstance);
1007     if (!tb) {
1008         code = BZNOENT;
1009         goto fail;
1010     }
1011
1012     /* setup return code */
1013     code = 0;
1014
1015     bnode_Hold(tb);
1016     bnode_SetStat(tb, BSTAT_SHUTDOWN);
1017     code = bnode_WaitStatus(tb, BSTAT_SHUTDOWN);        /* this can fail */
1018     bnode_ResetErrorCount(tb);
1019     bnode_SetStat(tb, BSTAT_NORMAL);
1020     bnode_Release(tb);
1021
1022   fail:
1023     osi_auditU(acall, BOS_RestartEvent, code, AUD_STR, ainstance, AUD_END);
1024     return code;
1025 }
1026
1027 /* set temp status */
1028 afs_int32
1029 SBOZO_SetTStatus(struct rx_call *acall, char *ainstance, afs_int32 astatus)
1030 {
1031     struct bnode *tb;
1032     afs_int32 code;
1033     char caller[MAXKTCNAMELEN];
1034
1035     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
1036         code = BZACCESS;
1037         goto fail;
1038     }
1039     if (DoLogging)
1040         bozo_Log("%s is executing SetTempStatus '%s'\n", caller, ainstance);
1041
1042     tb = bnode_FindInstance(ainstance);
1043     if (!tb) {
1044         code = BZNOENT;
1045         goto fail;
1046     }
1047     bnode_Hold(tb);
1048     bnode_ResetErrorCount(tb);
1049     code = bnode_SetStat(tb, astatus);
1050     bnode_Release(tb);
1051
1052   fail:
1053     osi_auditU(acall, BOS_SetTempStatusEvent, code, AUD_STR, ainstance,
1054                AUD_END);
1055     return code;
1056 }
1057
1058 afs_int32
1059 SBOZO_SetStatus(struct rx_call *acall, char *ainstance, afs_int32 astatus)
1060 {
1061     struct bnode *tb;
1062     afs_int32 code;
1063     char caller[MAXKTCNAMELEN];
1064
1065     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
1066         code = BZACCESS;
1067         goto fail;
1068     }
1069     if (DoLogging)
1070         bozo_Log("%s is executing SetStatus '%s' (status = %d)\n", caller,
1071                  ainstance, astatus);
1072
1073     tb = bnode_FindInstance(ainstance);
1074     if (!tb) {
1075         code = BZNOENT;
1076         goto fail;
1077     }
1078     bnode_Hold(tb);
1079     bnode_SetFileGoal(tb, astatus);
1080     code = bnode_SetStat(tb, astatus);
1081     bnode_Release(tb);
1082
1083   fail:
1084     osi_auditU(acall, BOS_SetStatusEvent, code, AUD_STR, ainstance, AUD_END);
1085     return code;
1086 }
1087
1088 afs_int32
1089 SBOZO_GetStatus(struct rx_call *acall, char *ainstance, afs_int32 *astat,
1090                 char **astatDescr)
1091 {
1092     struct bnode *tb;
1093     afs_int32 code;
1094
1095     tb = bnode_FindInstance(ainstance);
1096     if (!tb) {
1097         code = BZNOENT;
1098         goto fail;
1099     }
1100
1101     bnode_Hold(tb);
1102     code = bnode_GetStat(tb, astat);
1103     if (code) {
1104         bnode_Release(tb);
1105         goto fail;
1106     }
1107
1108     *astatDescr = (char *)malloc(BOZO_BSSIZE);
1109     code = bnode_GetString(tb, *astatDescr, BOZO_BSSIZE);
1110     bnode_Release(tb);
1111     if (code)
1112         (*astatDescr)[0] = 0;   /* null string means no further info */
1113     return 0;
1114
1115   fail:
1116     *astatDescr = (char *)malloc(1);
1117     **astatDescr = 0;
1118     return code;
1119 }
1120
1121 struct eidata {
1122     char *iname;
1123     int counter;
1124 };
1125
1126 static int
1127 eifunc(struct bnode *abnode, void *param)
1128 {
1129     struct eidata *arock = (struct eidata *)param;
1130
1131     if (arock->counter-- == 0) {
1132         /* done */
1133         strcpy(arock->iname, abnode->name);
1134         return 1;
1135     } else {
1136         /* not there yet */
1137         return 0;
1138     }
1139 }
1140
1141 static int
1142 ZapFile(const char *adir, const char *aname)
1143 {
1144     char tbuffer[256];
1145     if (snprintf(tbuffer, 256, "%s/%s", adir, aname)<256)
1146         return unlink(tbuffer);
1147     else
1148         return -1;
1149 }
1150
1151 afs_int32
1152 SBOZO_Prune(struct rx_call *acall, afs_int32 aflags)
1153 {
1154     afs_int32 code;
1155     DIR *dirp;
1156     struct dirent *tde;
1157     int i;
1158     char caller[MAXKTCNAMELEN];
1159
1160     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
1161         code = BZACCESS;
1162         goto fail;
1163     }
1164     if (bozo_isrestricted) {
1165         code = BZACCESS;
1166         goto fail;
1167     }
1168     if (DoLogging)
1169         bozo_Log("%s is executing Prune (flags=%d)\n", caller, aflags);
1170
1171     /* first scan AFS binary directory */
1172     dirp = opendir(AFSDIR_SERVER_BIN_DIRPATH);
1173     if (dirp) {
1174         for (tde = readdir(dirp); tde; tde = readdir(dirp)) {
1175             i = strlen(tde->d_name);
1176             if (aflags & BOZO_PRUNEOLD) {
1177                 if (i >= 4 && strncmp(tde->d_name + i - 4, ".OLD", 4) == 0)
1178                     ZapFile(AFSDIR_SERVER_BIN_DIRPATH, tde->d_name);
1179             }
1180             if (aflags & BOZO_PRUNEBAK) {
1181                 if (i >= 4 && strncmp(tde->d_name + i - 4, ".BAK", 4) == 0)
1182                     ZapFile(AFSDIR_SERVER_BIN_DIRPATH, tde->d_name);
1183             }
1184         }
1185         closedir(dirp);
1186     }
1187
1188     /* then scan AFS log directory */
1189     dirp = opendir(AFSDIR_SERVER_LOGS_DIRPATH);
1190     if (dirp) {
1191         for (tde = readdir(dirp); tde; tde = readdir(dirp)) {
1192             if (aflags & BOZO_PRUNECORE) {
1193                 if (strncmp(tde->d_name, AFSDIR_CORE_FILE, 4) == 0)
1194                     ZapFile(AFSDIR_SERVER_LOGS_DIRPATH, tde->d_name);
1195             }
1196         }
1197         closedir(dirp);
1198     }
1199     code = 0;
1200
1201   fail:
1202     osi_auditU(acall, BOS_PruneLogs, code, AUD_END);
1203     return code;
1204 }
1205
1206 afs_int32
1207 SBOZO_EnumerateInstance(struct rx_call *acall, afs_int32 anum,
1208                         char **ainstance)
1209 {
1210     struct eidata tdata;
1211
1212     *ainstance = (char *)malloc(BOZO_BSSIZE);
1213     **ainstance = 0;
1214     tdata.counter = anum;
1215     tdata.iname = *ainstance;
1216     bnode_ApplyInstance(eifunc, &tdata);
1217     if (tdata.counter >= 0)
1218         return BZDOM;           /* anum > # of actual instances */
1219     else
1220         return 0;
1221 }
1222
1223 struct bozo_bosEntryStats bozo_bosEntryStats[] = {
1224     {NULL, 1, 1, 0755, 02},     /* AFSDIR_SERVER_AFS_DIRPATH    */
1225     {NULL, 1, 1, 0755, 02},     /* AFSDIR_SERVER_ETC_DIRPATH    */
1226     {NULL, 1, 1, 0755, 02},     /* AFSDIR_SERVER_BIN_DIRPATH    */
1227     {NULL, 1, 1, 0755, 02},     /* AFSDIR_SERVER_LOGS_DIRPATH   */
1228     {NULL, 1, 0, 0700, 07},     /* AFSDIR_SERVER_BACKUP_DIRPATH */
1229     {NULL, 1, 1, 0700, 07},     /* AFSDIR_SERVER_DB_DIRPATH     */
1230     {NULL, 1, 1, 0700, 07},     /* AFSDIR_SERVER_LOCAL_DIRPATH  */
1231     {NULL, 0, 1, 0600, 07},     /* AFSDIR_SERVER_KEY_FILEPATH   */
1232     {NULL, 0, 1, 0600, 03}
1233 };                              /* AFSDIR_SERVER_ULIST_FILEPATH */
1234 int bozo_nbosEntryStats =
1235     sizeof(bozo_bosEntryStats) / sizeof(bozo_bosEntryStats[0]);
1236
1237 /* This function performs initialization of the bozo_bosEntrystats[]
1238  * array. This array contains the list of dirs that the bosserver
1239  * is interested in along with their recommended permissions
1240  * NOTE: This initialization is a bit ugly. This was caused because
1241  * the path names require procedural as opposed to static initialization.
1242  * The other fields in the struct are however, statically initialized.
1243  */
1244 int
1245 initBosEntryStats(void)
1246 {
1247     bozo_bosEntryStats[0].path = AFSDIR_SERVER_AFS_DIRPATH;
1248     bozo_bosEntryStats[1].path = AFSDIR_SERVER_ETC_DIRPATH;
1249     bozo_bosEntryStats[2].path = AFSDIR_SERVER_BIN_DIRPATH;
1250     bozo_bosEntryStats[3].path = AFSDIR_SERVER_LOGS_DIRPATH;
1251     bozo_bosEntryStats[4].path = AFSDIR_SERVER_BACKUP_DIRPATH;
1252     bozo_bosEntryStats[5].path = AFSDIR_SERVER_DB_DIRPATH;
1253     bozo_bosEntryStats[6].path = AFSDIR_SERVER_LOCAL_DIRPATH;
1254     bozo_bosEntryStats[7].path = AFSDIR_SERVER_KEY_FILEPATH;
1255     bozo_bosEntryStats[8].path = AFSDIR_SERVER_ULIST_FILEPATH;
1256
1257     return 0;
1258 }
1259
1260 /* StatEachEntry - If it's not there, it is okay.  If anything else goes wrong
1261  * complain.  Otherwise check permissions: shouldn't allow write or (usually)
1262  * read. */
1263
1264 static int
1265 StatEachEntry(IN struct bozo_bosEntryStats *stats)
1266 {
1267     struct stat info;
1268     if (stat(stats->path, &info)) {
1269         if (errno == ENOENT)
1270             return 1;           /* no such entry: just ignore it */
1271         return 0;               /* something else went wrong */
1272     } else {
1273         int rights;
1274         if (((info.st_mode & S_IFDIR) != 0) != stats->dir)
1275             return 0;           /* not expected type */
1276         if (stats->rootOwner && (info.st_uid != 0))
1277             return 0;           /* not owned by root */
1278         rights = (info.st_mode & 0000777);
1279         if ((rights & stats->reqPerm) != stats->reqPerm)
1280             return 0;           /* required permissions not present */
1281         if ((rights & stats->proPerm) != 0)
1282             return 0;           /* prohibited permissions present */
1283     }
1284     return 1;
1285 }
1286
1287 /* DirAccessOK - checks the mode bits on the AFS dir and decendents and
1288  * returns 0 if some are not OK and 1 otherwise.  For efficiency, it doesn't do
1289  * this check more often than every 5 seconds. */
1290
1291 int
1292 DirAccessOK(void)
1293 {
1294 #ifdef AFS_NT40_ENV
1295     /* underlying filesystem may not support directory protection */
1296     return 1;
1297 #else
1298     static afs_uint32 lastTime = 0;
1299     afs_uint32 now = FT_ApproxTime();
1300     static int lastResult = -1;
1301     int result;
1302     int i;
1303
1304     if ((now - lastTime) < 5)
1305         return lastResult;
1306     lastTime = now;
1307
1308     result = 1;
1309     for (i = 0; i < bozo_nbosEntryStats; i++) {
1310         struct bozo_bosEntryStats *e = &bozo_bosEntryStats[i];
1311         if (!StatEachEntry(e)) {
1312             bozo_Log("unhappy with %s which is a %s that should "
1313                      "have at least rights %o, at most rights %o %s\n",
1314                      e->path, e->dir ? "dir" : "file", e->reqPerm,
1315                      (~e->proPerm & 0777),
1316                      e->rootOwner ? ", owned by root" : "");
1317             result = 0;
1318             break;
1319         }
1320     }
1321
1322     if (result != lastResult) { /* log changes */
1323         bozo_Log("Server directory access is %sokay\n",
1324                  (result ? "" : "not "));
1325     }
1326     lastResult = result;
1327     return lastResult;
1328 #endif /* AFS_NT40_ENV */
1329 }
1330
1331 int
1332 GetRequiredDirPerm(const char *path)
1333 {
1334     int i;
1335     for (i = 0; i < bozo_nbosEntryStats; i++)
1336         if (strcmp(path, bozo_bosEntryStats[i].path) == 0)
1337             return bozo_bosEntryStats[i].reqPerm;
1338     return -1;
1339 }
1340
1341 afs_int32
1342 SBOZO_GetInstanceInfo(IN struct rx_call *acall,
1343                       IN char *ainstance,
1344                       OUT char **atype,
1345                       OUT struct bozo_status *astatus)
1346 {
1347     struct bnode *tb;
1348
1349     tb = bnode_FindInstance(ainstance);
1350     *atype = (char *)malloc(BOZO_BSSIZE);
1351     **atype = 0;
1352     if (!tb)
1353         return BZNOENT;
1354     if (tb->type)
1355         strcpy(*atype, tb->type->name);
1356     else
1357         (*atype)[0] = 0;        /* null string */
1358     memset(astatus, 0, sizeof(struct bozo_status));     /* good defaults */
1359     astatus->goal = tb->goal;
1360     astatus->fileGoal = tb->fileGoal;
1361     astatus->procStartTime = tb->procStartTime;
1362     astatus->procStarts = tb->procStarts;
1363     astatus->lastAnyExit = tb->lastAnyExit;
1364     astatus->lastErrorExit = tb->lastErrorExit;
1365     astatus->errorCode = tb->errorCode;
1366     astatus->errorSignal = tb->errorSignal;
1367     if (tb->flags & BNODE_ERRORSTOP)
1368         astatus->flags |= BOZO_ERRORSTOP;
1369     if (bnode_HasCore(tb))
1370         astatus->flags |= BOZO_HASCORE;
1371     if (!DirAccessOK())
1372         astatus->flags |= BOZO_BADDIRACCESS;
1373     return 0;
1374 }
1375
1376 afs_int32
1377 SBOZO_GetInstanceParm(struct rx_call *acall,
1378                       char *ainstance,
1379                       afs_int32 anum,
1380                       char **aparm)
1381 {
1382     struct bnode *tb;
1383     char *tp;
1384     afs_int32 code;
1385
1386     tp = (char *)malloc(BOZO_BSSIZE);
1387     *aparm = tp;
1388     *tp = 0;                    /* null-terminate string in error case */
1389     tb = bnode_FindInstance(ainstance);
1390     if (!tb)
1391         return BZNOENT;
1392     bnode_Hold(tb);
1393     if (anum == 999) {
1394         if (tb->notifier) {
1395             memcpy(tp, tb->notifier, strlen(tb->notifier) + 1);
1396             code = 0;
1397         } else
1398             code = BZNOENT;     /* XXXXX */
1399     } else
1400         code = bnode_GetParm(tb, anum, tp, BOZO_BSSIZE);
1401     bnode_Release(tb);
1402
1403     /* Not Currently Audited */
1404     return code;
1405 }
1406
1407 afs_int32
1408 SBOZO_GetLog(struct rx_call *acall, char *aname)
1409 {
1410     afs_int32 code;
1411     FILE *tfile;
1412     int tc;
1413     char *logpath;
1414     char buffer;
1415     char caller[MAXKTCNAMELEN];
1416
1417     /* Check access since 'aname' could specify a file outside of the
1418      * AFS log directory (which is bosserver's working directory).
1419      */
1420     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
1421         code = BZACCESS;
1422         goto fail;
1423     }
1424     if (bozo_isrestricted && strchr(aname, '/')
1425         && strcmp(aname, AFSDIR_CANONICAL_SERVER_SLVGLOG_FILEPATH)) {
1426         code = BZACCESS;
1427         goto fail;
1428     }
1429
1430     /* construct local path from canonical (wire-format) path */
1431     if (ConstructLocalLogPath(aname, &logpath)) {
1432         return BZNOENT;
1433     }
1434     if (DoLogging)
1435         bozo_Log("%s is executing GetLog '%s'\n", caller, logpath);
1436     tfile = fopen(logpath, "r");
1437     free(logpath);
1438
1439     if (!tfile) {
1440         return BZNOENT;
1441     }
1442
1443     while (1) {
1444         tc = getc(tfile);
1445         if (tc == 0)
1446             continue;           /* our termination condition on other end */
1447         if (tc == EOF)
1448             break;
1449         buffer = tc;
1450         if (rx_Write(acall, &buffer, 1) != 1) {
1451             fclose(tfile);
1452             code = BZNET;
1453             goto fail;
1454         }
1455     }
1456
1457     /* all done, cleanup and return */
1458     fclose(tfile);
1459
1460     /* write out the end delimeter */
1461     buffer = 0;
1462     if (rx_Write(acall, &buffer, 1) != 1)
1463         return BZNET;
1464     code = 0;
1465
1466   fail:
1467     osi_auditU(acall, BOS_GetLogsEvent, code, AUD_END);
1468     return code;
1469 }
1470
1471 afs_int32
1472 SBOZO_GetInstanceStrings(struct rx_call *acall, char *abnodeName,
1473                          char **as1, char **as2, char **as3, char **as4)
1474 {
1475     struct bnode *tb;
1476
1477     *as2 = (char *)malloc(1);
1478     **as2 = 0;
1479     *as3 = (char *)malloc(1);
1480     **as3 = 0;
1481     *as4 = (char *)malloc(1);
1482     **as4 = 0;
1483     tb = bnode_FindInstance(abnodeName);
1484     if (!tb)
1485         goto fail;
1486
1487     /* now, return the appropriate error string, if any */
1488     if (tb->lastErrorName) {
1489         *as1 = (char *)malloc(strlen(tb->lastErrorName) + 1);
1490         strcpy(*as1, tb->lastErrorName);
1491     } else {
1492         *as1 = (char *)malloc(1);
1493         **as1 = 0;
1494     }
1495     return 0;
1496
1497   fail:
1498     *as1 = (char *)malloc(1);
1499     **as1 = 0;
1500     return BZNOENT;
1501 }
1502
1503 afs_int32
1504 SBOZO_GetRestrictedMode(struct rx_call *acall, afs_int32 *arestmode)
1505 {
1506     *arestmode = bozo_isrestricted;
1507     return 0;
1508 }
1509
1510 afs_int32
1511 SBOZO_SetRestrictedMode(struct rx_call *acall, afs_int32 arestmode)
1512 {
1513     afs_int32 code;
1514     char caller[MAXKTCNAMELEN];
1515
1516     if (!afsconf_SuperUser(bozo_confdir, acall, caller)) {
1517         return BZACCESS;
1518     }
1519     if (bozo_isrestricted) {
1520         return BZACCESS;
1521     }
1522     if (arestmode != 0 && arestmode != 1) {
1523         return BZDOM;
1524     }
1525     bozo_isrestricted = arestmode;
1526     code = WriteBozoFile(0);
1527
1528     return code;
1529 }
1530
1531 void *
1532 bozo_ShutdownAndExit(void *param)
1533 {
1534     int asignal = (intptr_t)param;
1535     int code;
1536
1537     bozo_Log
1538         ("Shutdown of BOS server and processes in response to signal %d\n",
1539          asignal);
1540
1541     /* start shutdown of all processes */
1542     if ((code = bnode_ApplyInstance(sdproc, NULL)) == 0) {
1543         /* wait for shutdown to complete */
1544         code = bnode_ApplyInstance(swproc, NULL);
1545     }
1546
1547     if (code) {
1548         bozo_Log("Shutdown incomplete (code = %d); manual cleanup required\n",
1549                  code);
1550     }
1551
1552     rx_Finalize();
1553     exit(code);
1554 }