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