Move key-related warnings to common server code
[openafs.git] / src / butc / tcmain.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 #include <afs/procmgmt.h>
14
15 #include <roken.h>
16 #include <afs/opr.h>
17
18 #ifdef IGNORE_SOME_GCC_WARNINGS
19 # pragma GCC diagnostic warning "-Wimplicit-function-declaration"
20 #endif
21
22 #ifdef AFS_NT40_ENV
23 #include <WINNT/afsevent.h>
24 #endif
25
26 #include <ctype.h>
27
28 #include <rx/rx.h>
29 #include <rx/rx_globals.h>
30 #include <rx/rxkad.h>
31 #include <rx/xdr.h>
32
33 #include <afs/afsint.h>
34 #include <afs/prs_fs.h>
35 #include <afs/nfs.h>
36 #include <afs/vlserver.h>
37 #include <lwp.h>
38 #include <lock.h>
39 #include <afs/afsutil.h>
40 #include <afs/authcon.h>
41 #include <afs/cellconfig.h>
42 #include <afs/keys.h>
43 #include <afs/volser.h>
44 #include <ubik.h>
45 #include <afs/audit.h>
46 #include <afs/com_err.h>
47 #include <afs/cmd.h>
48 #include <afs/tcdata.h>
49 #include <afs/bubasics.h>
50 #include <afs/budb_errs.h>
51 #include <afs/budb_client.h>
52 #include <afs/bucoord_prototypes.h>
53 #include <afs/butx.h>
54 #include <afs/kautils.h>
55 #include <afs/bc.h>
56
57 #include "error_macros.h"
58 #define XBSA_TCMAIN
59 #include "butc_xbsa.h"
60 #include "butc_prototypes.h"
61 #include "butc_internal.h"
62
63 #define N_SECURITY_OBJECTS 3
64 #define ERRCODE_RANGE 8         /* from error_table.h */
65
66 #define TE_PREFIX  "TE"
67 #define TL_PREFIX  "TL"
68 #define CFG_PREFIX "CFG"
69
70 extern struct ubik_client *cstruct;
71 FILE *logIO, *ErrorlogIO, *centralLogIO, *lastLogIO;
72 char lFile[AFSDIR_PATH_MAX];
73 char logFile[AFSDIR_PATH_MAX + 256];
74 char ErrorlogFile[AFSDIR_PATH_MAX + 256];
75 char lastLogFile[AFSDIR_PATH_MAX + 256];
76 char eFile[AFSDIR_PATH_MAX];
77 char tapeConfigFile[AFSDIR_PATH_MAX];
78 char pFile[AFSDIR_PATH_MAX];
79 int debugLevel = 0;
80 struct tapeConfig globalTapeConfig;
81 struct deviceSyncNode *deviceLatch;
82 char globalCellName[64];
83 char *whoami = "butc";
84
85 /* GLOBAL CONFIGURATION PARAMETERS */
86 int dump_namecheck;
87 int queryoperator;
88 int autoQuery;
89 int isafile;
90 int tapemounted;
91 char *opencallout;
92 char *closecallout;
93 char *restoretofile;
94 int forcemultiple;
95
96 int maxpass;
97 #define PASSESMIN  1
98 #define PASSESMAX  10
99 #define PASSESDFLT 2
100 afs_int32 groupId;
101 #define MINGROUPID 0x1
102 #define MAXGROUPID 0x7FFFFFFF
103 afs_int32 statusSize;
104 #define MINSTATUS  1
105 #define MAXSTATUS  0x7fffffff
106 afs_int32 BufferSize;           /* Size in B stored for data */
107 char *centralLogFile;
108 afs_int32 lastLog;              /* Log last pass info */
109 int rxBind = 0;
110 struct afsconf_dir *butc_confdir;
111 int allow_unauth = 0;
112
113 #define ADDRSPERSITE 16         /* Same global is in rx/rx_user.c */
114 afs_uint32 SHostAddrs[ADDRSPERSITE];
115
116 static afs_int32
117 SafeATOL(char *anum)
118 {
119     afs_int32 total;
120     int tc;
121
122     total = 0;
123     while ((tc = *anum)) {
124         if (tc < '0' || tc > '9')
125             return -1;
126         total *= 10;
127         total += (tc - '0');
128         anum++;
129     }
130     return total;
131 }
132
133 /* atocl
134  *      Convert a string into an afs_int32.
135  *      Returned afs_int32 is in Bytes, Kb, Mb, Gb, or Tb. Based on crunit char.
136  *      This routine only converts unsigned float values.
137  *      The returned value is a whole number.
138  * entry:
139  *      numstring - text string to be converted.
140  *      crunit - value returned in 'B', 'K', 'M', 'G', 'T'.
141  *               ' ' or NULL ==> 'B' (bytes).
142  * exit:
143  *      number - returned value in requested crunit - rounded
144  *               to nearest whole number.
145  * fn return value:
146  *       0 - conversion ok
147  *      -1 - error in conversion
148  * notes:
149  *      should deal with signed numbers. Should signal error if no digits
150  *      seen.
151  */
152 int
153 atocl(char *numstring, char crunit, afs_int32 *number)
154 {
155     float total;
156     afs_int32 runits;
157     char cunit;
158     afs_int32 units;
159     afs_int32 count;
160     char rest[256];
161
162     /* Determine which units to report in */
163     switch (crunit) {
164     case 't':
165     case 'T':
166         runits = 12;
167         break;
168
169     case 'g':
170     case 'G':
171         runits = 9;
172         break;
173
174     case 'm':
175     case 'M':
176         runits = 6;
177         break;
178
179     case 'k':
180     case 'K':
181         runits = 3;
182         break;
183
184     case 'b':
185     case 'B':
186     case ' ':
187     case 0:
188         runits = 0;
189         break;
190
191     default:
192         return (-1);
193     }
194
195     count =
196         sscanf(numstring, "%f%c%s", &total, &cunit, rest);
197     if ((count > 2) || (count <= 0))
198         return -1;
199     if (count == 1)
200         cunit = 'B';            /* bytes */
201
202     switch (cunit) {
203     case 't':
204     case 'T':
205         units = 12;
206         break;
207
208     case 'g':
209     case 'G':
210         units = 9;
211         break;
212
213     case 'm':
214     case 'M':
215         units = 6;
216         break;
217
218     case 'k':
219     case 'K':
220         units = 3;
221         break;
222
223     case 'b':
224     case 'B':
225     case ' ':
226     case 0:
227         units = 0;
228         break;
229
230     default:
231         return (-1);
232     }
233
234     /* Go to correct unit */
235     for (; units < runits; units += 3)
236         total /= 1024.0;
237     for (; units > runits; units -= 3)
238         total *= 1024.0;
239
240     total += 0.5;               /* Round up */
241     if ((total >= 2147483648.0) || (total < 0)) /* Don't go over 2G */
242         *number = 2147483647;
243     else
244         *number = total;
245
246     return (0);
247 }
248
249 static int
250 stringNowReplace(char *logFile, char *deviceName)
251 {
252     char *pos = 0;
253     char storeDevice[256];
254     int mvFlag = 0, devPrefLen;
255 #ifdef AFS_NT40_ENV
256     char devPrefix[] = "\\\\.";
257 #else
258     char devPrefix[] = "/dev";
259 #endif
260
261     devPrefLen = strlen(devPrefix);
262     strcpy(storeDevice, deviceName);
263     if (strncmp(deviceName, devPrefix, devPrefLen) == 0) {
264         deviceName += devPrefLen;
265         mvFlag++;
266     }
267     while ((pos = strchr(deviceName, devPrefix[0])))    /* look for / or \ */
268         *pos = '_';
269     strcat(logFile, deviceName);
270     /* now put back deviceName to the way it was */
271     if (mvFlag)
272         deviceName -= devPrefLen;
273
274     strcpy(deviceName, storeDevice);
275
276     return (0);
277 }
278
279
280 /* GetDeviceConfig
281  *      get the configuration information for a particular tape device
282  *      as specified by the portoffset
283  * entry:
284  *      filename - full pathname of file containing the tape device
285  *              configuration information
286  *      config - for return results
287  *      portOffset - for which configuration is required
288  * notes:
289  *      logging not available when this routine is called
290  *      caller return value checks
291  * exit:
292  *      0 => Found entry with same port, return info in config.
293  *     -1 => Error encountered trying to read the file.
294  *      1 => Desired entry does not exist or file does not exist.
295  */
296
297 #define LINESIZE        256
298 static afs_int32
299 GetDeviceConfig(char *filename, struct tapeConfig *config, afs_int32 portOffset)
300 {
301     FILE *devFile = 0;
302     char line[LINESIZE];
303     char devName[LINESIZE], tcapacity[LINESIZE], tfmsize[LINESIZE],
304         trest[LINESIZE];
305     afs_int32 aport;
306     afs_int32 capacity;
307     afs_int32 fmSize;
308     afs_int32 code = 0, count;
309
310     /* Initialize the config struct */
311     config->capacity = 0;
312     config->fileMarkSize = 0;
313     config->portOffset = portOffset;
314     strcpy(config->device, "");
315
316     devFile = fopen(filename, "r");
317     if (!devFile) {
318         if (errno == ENOENT)
319             ERROR_EXIT(1);
320         fprintf(stderr, "Error %d: Can't open %s\n", errno, filename);
321         ERROR_EXIT(-1);
322     }
323
324     while (fgets(line, LINESIZE - 1, devFile)) {
325         count =
326             sscanf(line, "%s %s %s %u%s\n", tcapacity, tfmsize, devName,
327                    &aport, trest);
328
329         if (count == 4 || count == 5) {
330             if (atocl(tcapacity, 'K', &capacity)) {
331                 fprintf(stderr,
332                         "tapeconfig: Tape capacity parse error in: %s\n",
333                         line);
334                 ERROR_EXIT(-1);
335             }
336             if (atocl(tfmsize, 'B', &fmSize)) {
337                 fprintf(stderr,
338                         "tapeconfig: File-mark size parse error in: %s\n",
339                         line);
340                 ERROR_EXIT(-1);
341             }
342         } else {
343             count = sscanf(line, "%s %u%s\n", devName, &aport, trest);
344             if (count == 2 || count == 3) {
345                 capacity = 0x7fffffff;
346                 fmSize = 0;
347             } else {
348                 fprintf(stderr, "tapeconfig: Parse error in: %s\n", line);
349                 ERROR_EXIT(-1);
350             }
351         }
352
353         if ((aport < 0) || (aport > BC_MAXPORTOFFSET)) {
354             fprintf(stderr, "tapeconfig: Port offset parse error in: %s\n",
355                     line);
356             ERROR_EXIT(-1);
357         }
358
359         if (aport != portOffset)
360             continue;
361
362         if (fmSize < 0) {
363             fprintf(stderr, "Invalid file mark size, %d, in: %s\n", fmSize,
364                     line);
365             ERROR_EXIT(-1);
366         }
367
368         config->capacity = capacity;
369         config->fileMarkSize = fmSize;
370         config->portOffset = aport;
371         strncpy(config->device, devName, 100);
372
373         ERROR_EXIT(0);
374     }
375
376     /* fprintf(stderr, "Can't find tapeconfig entry for port offset %d\n", portOffset); */
377     ERROR_EXIT(1);
378
379   error_exit:
380     if (devFile)
381         fclose(devFile);
382     return (code);
383 }
384
385 /* GetConfigParams
386  */
387 static afs_int32
388 GetConfigParams(char *filename, afs_int32 port)
389 {
390     char paramFile[AFSDIR_PATH_MAX + 257];
391     FILE *devFile = 0;
392     char line[LINESIZE], cmd[LINESIZE], value[LINESIZE];
393     afs_int32 code = 0;
394     int cnt;
395
396     /* DEFAULT SETTINGS FOR GLOBAL PARAMETERS */
397     dump_namecheck = 1;         /* check tape name on dumps */
398     queryoperator = 1;          /* can question operator */
399     autoQuery = 1;              /* prompt for first tape */
400     isafile = 0;                /* Do not dump to a file */
401     opencallout = NULL;         /* open  callout routine */
402     closecallout = NULL;        /* close callout routine */
403     tapemounted = 0;            /* tape is not mounted */
404 #ifdef xbsa
405     BufferSize = (CONF_XBSA ? XBSADFLTBUFFER : BUTM_BLOCKSIZE);
406     dumpRestAuthnLevel = rpc_c_protect_level_default;
407     xbsaObjectOwner = NULL;     /* bsaObjectOwner */
408     appObjectOwner = NULL;      /* appObjectOwner */
409     adsmServerName = NULL;      /* TSM server name - same as ADSM */
410     xbsaSecToken = NULL;        /* XBSA sercurity token */
411     xbsalGName = NULL;          /* XBSA IGName */
412 #else
413     BufferSize = BUTM_BLOCKSIZE;
414 #endif /*xbsa */
415     centralLogFile = NULL;      /* Log for all butcs */
416     centralLogIO = 0;           /* Log for all butcs */
417     statusSize = 0;             /* size before status message */
418     maxpass = PASSESDFLT;       /* dump passes */
419     lastLog = 0;                /* separate log for last pass */
420     lastLogIO = 0;              /* separate log for last pass */
421     groupId = 0;                /* Group id for multiple dumps */
422
423     /* Try opening the CFG_<port> file */
424     snprintf(paramFile, sizeof(paramFile), "%s_%d", filename, port);
425     devFile = fopen(paramFile, "r");
426     if (devFile) {
427         /* Set log names to TL_<port>, TL_<port>.lp and TE_<port> */
428         snprintf(logFile, sizeof(logFile), "%s_%d", lFile, port);
429         snprintf(lastLogFile, sizeof(lastLogFile), "%s_%d.lp", lFile, port);
430         snprintf(ErrorlogFile, sizeof(ErrorlogFile), "%s_%d", eFile, port);
431     } else if (CONF_XBSA) {
432         /* If configured as XBSA, a configuration file CFG_<port> must exist */
433         printf("Cannot open configuration file %s", paramFile);
434         ERROR_EXIT(1);
435     } else {
436         /* Try the CFG_<device> name as the device file */
437         strcpy(paramFile, filename);
438         stringNowReplace(paramFile, globalTapeConfig.device);
439         /* Set log names to TL_<device>, TL_<device> and TE_<device> */
440         strcpy(logFile, lFile);
441         stringNowReplace(logFile, globalTapeConfig.device);
442         strcpy(lastLogFile, lFile);
443         stringNowReplace(lastLogFile, globalTapeConfig.device);
444         strcat(lastLogFile, ".lp");
445         strcpy(ErrorlogFile, eFile);
446         stringNowReplace(ErrorlogFile, globalTapeConfig.device);
447
448         /* Now open the device file */
449         devFile = fopen(paramFile, "r");
450         if (!devFile)
451             ERROR_EXIT(0);      /* CFG file doesn't exist for non-XBSA and that's ok */
452     }
453
454     /* Read each line of the Configuration file */
455     while (fgets(line, LINESIZE - 1, devFile)) {
456         cnt = sscanf(line, "%s %s", cmd, value);
457         if (cnt != 2) {
458             if (cnt > 0)
459                 printf("Bad line in %s: %s\n", paramFile, line);
460             continue;
461         }
462
463         for (cnt = 0; cnt < strlen(cmd); cnt++)
464             if (islower(cmd[cnt]))
465                 cmd[cnt] = toupper(cmd[cnt]);
466
467         if (!strcmp(cmd, "NAME_CHECK")) {
468             if (CONF_XBSA) {
469                 printf
470                     ("Warning: The %s parameter is ignored with a Backup Service\n",
471                      cmd);
472                 continue;
473             }
474
475             for (cnt = 0; cnt < strlen(value); cnt++)
476                 if (islower(value[cnt]))
477                     value[cnt] = toupper(value[cnt]);
478
479             if (!strcmp(value, "NO")) {
480                 printf("Dump tape name check is disabled\n");
481                 dump_namecheck = 0;
482             } else {
483                 printf("Dump tape name check is enabled\n");
484                 dump_namecheck = 1;
485             }
486         }
487
488         else if (!strcmp(cmd, "MOUNT")) {
489             if (CONF_XBSA) {
490                 printf
491                     ("Warning: The %s parameter is ignored with a Backup Service\n",
492                      cmd);
493                 continue;
494             }
495
496             opencallout = strdup(value);
497             printf("Tape mount callout routine is %s\n", opencallout);
498         }
499
500         else if (!strcmp(cmd, "UNMOUNT")) {
501             if (CONF_XBSA) {
502                 printf
503                     ("Warning: The %s parameter is ignored with a Backup Service\n",
504                      cmd);
505                 continue;
506             }
507
508             closecallout = strdup(value);
509             printf("Tape unmount callout routine is %s\n", closecallout);
510         }
511
512         else if (!strcmp(cmd, "ASK")) {
513             for (cnt = 0; cnt < strlen(value); cnt++)
514                 if (islower(value[cnt]))
515                     value[cnt] = toupper(value[cnt]);
516
517             if (!strcmp(value, "NO")) {
518                 printf("Operator queries are disabled\n");
519                 queryoperator = 0;
520             } else {
521                 printf("Operator queries are enabled\n");
522                 queryoperator = 1;
523             }
524         }
525
526         else if (!strcmp(cmd, "FILE")) {
527             if (CONF_XBSA) {
528                 printf
529                     ("Warning: The %s parameter is ignored with a Backup Service\n",
530                      cmd);
531                 continue;
532             }
533
534             for (cnt = 0; cnt < strlen(value); cnt++)
535                 if (islower(value[cnt]))
536                     value[cnt] = toupper(value[cnt]);
537
538             if (!strcmp(value, "YES")) {
539                 printf("Will dump to a file\n");
540                 isafile = 1;
541             } else {
542                 printf("Will not dump to a file\n");
543                 isafile = 0;
544             }
545         }
546
547         else if (!strcmp(cmd, "AUTOQUERY")) {
548             if (CONF_XBSA) {
549                 printf
550                     ("Warning: The %s parameter is ignored with a Backup Service\n",
551                      cmd);
552                 continue;
553             }
554
555             for (cnt = 0; cnt < strlen(value); cnt++)
556                 if (islower(value[cnt]))
557                     value[cnt] = toupper(value[cnt]);
558
559             if (!strcmp(value, "NO")) {
560                 printf("Auto query is disabled\n");
561                 autoQuery = 0;
562             } else {
563                 printf("Auto query is enabled\n");
564                 autoQuery = 1;
565             }
566         }
567
568         else if (!strcmp(cmd, "BUFFERSIZE")) {
569             afs_int32 size;
570             afs_int32 numTapeblocks;
571
572             if (!CONF_XBSA) {
573                 if (atocl(value, 'K', &size)) {
574                     fprintf(stderr, "BUFFERSIZE parse error\n");
575                     size = 0;
576                 }
577
578                 /* A tapeblock is 16KB. Determine # of tapeblocks. Then
579                  * determine BufferSize needed for that many tapeblocks.
580                  */
581                 numTapeblocks = size / 16;
582                 if (numTapeblocks <= 0)
583                     numTapeblocks = 1;
584                 printf("BUFFERSIZE is %u KBytes\n", (numTapeblocks * 16));
585                 BufferSize = numTapeblocks * BUTM_BLOCKSIZE;
586             } else {
587 #ifdef xbsa
588                 if (atocl(value, 'B', &size)) {
589                     fprintf(stderr, "BUFFERSIZE parse error\n");
590                     size = 0;
591                 }
592                 if (size < XBSAMINBUFFER)
593                     size = XBSAMINBUFFER;
594                 if (size > XBSAMAXBUFFER)
595                     size = XBSAMAXBUFFER;
596                 printf("XBSA buffer size is %u Bytes\n", size);
597                 BufferSize = size;
598 #endif
599             }
600         }
601 #ifndef xbsa
602         /* All the xbsa spacific parameters */
603         else if (!strcmp(cmd, "TYPE") || !strcmp(cmd, "NODE")
604                  || !strcmp(cmd, "SERVER") || !strcmp(cmd, "PASSWORD")
605                  || !strcmp(cmd, "PASSFILE") || !strcmp(cmd, "MGMTCLASS")) {
606             printf("This binary does not have XBSA support\n");
607             return 1;
608         }
609 #else
610         else if (!strcmp(cmd, "TYPE")) {        /* required for XBSA */
611             if (!CONF_XBSA) {
612                 printf
613                     ("Warning: The %s parameter is ignored with a tape drive\n",
614                      cmd);
615                 continue;
616             }
617
618             for (cnt = 0; (size_t) cnt < strlen(value); cnt++)
619                 if (islower(value[cnt]))
620                     value[cnt] = toupper(value[cnt]);
621
622             if (strcmp(value, "TSM") == 0) {
623                 xbsaType = XBSA_SERVER_TYPE_ADSM;       /* Known XBSA server type */
624             } else {
625                 printf("Configuration file error, %s %s is not recognized\n",
626                        cmd, value);
627                 xbsaType = XBSA_SERVER_TYPE_UNKNOWN;
628             }
629             printf("XBSA type is %s\n",
630                    ((xbsaType ==
631                      XBSA_SERVER_TYPE_UNKNOWN) ? "Unknown" : value));
632         }
633
634         else if (!strcmp(cmd, "NODE")) {
635             if (!CONF_XBSA) {
636                 printf
637                     ("Warning: The %s parameter is ignored with a tape drive\n",
638                      cmd);
639                 continue;
640             }
641             xbsaObjectOwner = strdup(value);
642             printf("XBSA node is %s\n", xbsaObjectOwner);
643         }
644
645         else if (!strcmp(cmd, "SERVER")) {      /* required for XBSA */
646             if (!CONF_XBSA) {
647                 printf
648                     ("Warning: The %s parameter is ignored with a tape drive\n",
649                      cmd);
650                 continue;
651             }
652             adsmServerName = strdup(value);
653             printf("XBSA server is %s\n", adsmServerName);
654         }
655
656         else if (!strcmp(cmd, "PASSWORD")) {    /* This or PASSFILE required for XBSA */
657             if (!CONF_XBSA) {
658                 printf
659                     ("Warning: The %s parameter is ignored with a tape drive\n",
660                      cmd);
661                 continue;
662             }
663             if (xbsaSecToken) {
664                 printf
665                     ("Warning: The %s parameter is ignored. Already read password\n",
666                      cmd);
667                 continue;
668             }
669
670             xbsaSecToken = strdup(value);
671             printf("XBSA Password has been read\n");
672         }
673
674         else if (!strcmp(cmd, "PASSFILE")) {    /* This or PASSWORD required for XBSA */
675             FILE *pwdFile;
676             if (!CONF_XBSA) {
677                 printf
678                     ("Warning: The %s parameter is ignored with a tape drive\n",
679                      cmd);
680                 continue;
681             }
682             if (xbsaSecToken) {
683                 printf
684                     ("Warning: The %s parameter is ignored. Already read password\n",
685                      cmd);
686                 continue;
687             }
688
689             pwdFile = fopen(value, "r");
690             if (!pwdFile) {
691                 printf
692                     ("Configuration file error, cannot open password file %s\n",
693                      value);
694                 ERROR_EXIT(1);
695             }
696             xbsaSecToken = malloc(LINESIZE);
697             if (!fscanf(pwdFile, "%s", xbsaSecToken)) {
698                 printf
699                     ("Configuration file error, cannot read password file %s\n",
700                      value);
701                 ERROR_EXIT(1);
702             }
703             printf("XBSA password retrieved from password file\n");
704         }
705
706         else if (!strcmp(cmd, "MGMTCLASS")) {   /* XBSA */
707             if (!CONF_XBSA) {
708                 printf
709                     ("Warning: The %s parameter is ignored with a tape drive\n",
710                      cmd);
711                 continue;
712             }
713             xbsalGName = strdup(value);
714             printf("XBSA management class is %s\n", xbsalGName);
715         }
716 #endif
717
718         else if (!strcmp(cmd, "MAXPASS")) {
719             maxpass = SafeATOL(value);
720             if (maxpass < PASSESMIN)
721                 maxpass = PASSESMIN;
722             if (maxpass > PASSESMAX)
723                 maxpass = PASSESMAX;
724             printf("MAXPASS is %d\n", maxpass);
725         }
726
727         else if (!strcmp(cmd, "GROUPID")) {
728             groupId = SafeATOL(value);
729             if ((groupId < MINGROUPID) || (groupId > MAXGROUPID)) {
730                 printf("Configuration file error, %s %s is invalid\n", cmd,
731                        value);
732                 ERROR_EXIT(1);
733             }
734             printf("Group Id is %d\n", groupId);
735         }
736
737         else if (!strcmp(cmd, "LASTLOG")) {
738             for (cnt = 0; (size_t) cnt < strlen(value); cnt++)
739                 if (islower(value[cnt]))
740                     value[cnt] = toupper(value[cnt]);
741
742             lastLog = (strcmp(value, "YES") == 0);
743             printf("Will %sgenerate a last log\n", (lastLog ? "" : "not "));
744         }
745
746         else if (!strcmp(cmd, "CENTRALLOG")) {
747             centralLogFile = strdup(value);
748             printf("Central log file is %s\n", centralLogFile);
749         }
750
751         else if (!strcmp(cmd, "STATUS")) {
752             if (atocl(value, 'B', &statusSize)) {
753                 fprintf(stderr, "STATUS parse error\n");
754                 statusSize = 0;
755             }
756             if (statusSize < MINSTATUS)
757                 statusSize = MINSTATUS;
758             if (statusSize > MAXSTATUS)
759                 statusSize = MAXSTATUS;
760         }
761
762         else {
763             printf("Warning: Unrecognized configuration parameter: %s", line);
764         }
765     }                           /*fgets */
766
767     if (statusSize) {
768         /* Statussize is in bytes and requires that BufferSize be set first */
769         statusSize *= BufferSize;
770         if (statusSize < 0)
771             statusSize = 0x7fffffff;    /*max size */
772         printf("Status every %ld Bytes\n", afs_printable_int32_ld(statusSize));
773     }
774
775   error_exit:
776     if (devFile)
777         fclose(devFile);
778
779     /* If the butc is configured as XBSA, check for required parameters */
780 #ifdef xbsa
781     if (!code && CONF_XBSA) {
782         if (xbsaType == XBSA_SERVER_TYPE_UNKNOWN) {
783             printf
784                 ("Configuration file error, the TYPE parameter must be specified, or\n");
785             printf("an entry must exist in %s for port %d\n", tapeConfigFile,
786                    port);
787             code = 1;
788         }
789         if (!adsmServerName) {
790             printf
791                 ("Configuration file error, the SERVER parameter must be specified\n");
792             code = 1;
793         }
794         if (!xbsaSecToken) {
795             printf
796                 ("Configuration file error, the PASSWORD or PASSFILE parameter must be specified\n");
797             code = 1;
798         }
799     }
800 #endif /*xbsa */
801     return (code);
802 }
803
804 #ifdef xbsa
805 static void
806 xbsa_shutdown(int x)
807 {
808     xbsa_Finalize(&butxInfo);
809     exit(0);
810 }
811 #endif
812
813 static int
814 tc_IsLocalRealmMatch(void *rock, char *name, char *inst, char *cell)
815 {
816     struct afsconf_dir *dir = (struct afsconf_dir *)rock;
817     afs_int32 islocal = 0;      /* default to no */
818     int code;
819
820     code = afsconf_IsLocalRealmMatch(dir, &islocal, name, inst, cell);
821     if (code) {
822         TLog(0, "Failed local realm check; code=%d, name=%s, inst=%s, cell=%s\n",
823                  code, name, inst, cell);
824     }
825     return islocal;
826 }
827
828 static int
829 WorkerBee(struct cmd_syndesc *as, void *arock)
830 {
831     afs_int32 code, numClasses;
832     struct rx_securityClass *(nullObjects[1]), **secObjs, **allObjs;
833     struct rx_service *service;
834     time_t tokenExpires;
835     char cellName[64];
836     int localauth;
837     /*process arguments */
838     afs_int32 portOffset = 0;
839 #ifdef AFS_PTHREAD_ENV
840     pthread_t dbWatcherPid;
841     pthread_attr_t tattr;
842     AFS_SIGSET_DECL;
843 #else
844     PROCESS dbWatcherPid;
845 #endif
846     char hoststr[16];
847     afs_uint32 host = htonl(INADDR_ANY);
848     char *auditIface = NULL;
849
850     debugLevel = 0;
851
852     /*initialize the error tables */
853     initialize_KA_error_table();
854     initialize_RXK_error_table();
855     initialize_KTC_error_table();
856     initialize_ACFG_error_table();
857     initialize_CMD_error_table();
858     initialize_VL_error_table();
859     initialize_BUTM_error_table();
860     initialize_BUTC_error_table();
861 #ifdef xbsa
862     initialize_BUTX_error_table();
863 #endif /*xbs */
864     initialize_VOLS_error_table();
865     initialize_BUDB_error_table();
866     initialize_BUCD_error_table();
867
868     if (as->parms[0].items) {
869         portOffset = SafeATOL(as->parms[0].items->data);
870         if (portOffset == -1) {
871             fprintf(stderr, "Illegal port offset '%s'\n",
872                     as->parms[0].items->data);
873             exit(1);
874         } else if (portOffset > BC_MAXPORTOFFSET) {
875             fprintf(stderr, "%u exceeds max port offset %u\n", portOffset,
876                     BC_MAXPORTOFFSET);
877             exit(1);
878         }
879     }
880
881     xbsaType = XBSA_SERVER_TYPE_NONE;   /* default */
882     if (as->parms[3].items) {   /* -device */
883         globalTapeConfig.capacity = 0x7fffffff; /* 2T for max tape capacity */
884         globalTapeConfig.fileMarkSize = 0;
885         globalTapeConfig.portOffset = portOffset;
886         strncpy(globalTapeConfig.device, as->parms[3].items->data, 100);
887         xbsaType = XBSA_SERVER_TYPE_NONE;       /* Not XBSA */
888     } else {
889         /* Search for an entry in tapeconfig file */
890         code = GetDeviceConfig(tapeConfigFile, &globalTapeConfig, portOffset);
891         if (code == -1) {
892             fprintf(stderr, "Problem in reading config file %s\n",
893                     tapeConfigFile);
894             exit(1);
895         }
896         /* Set xbsaType. If code == 1, no entry was found in the tapeconfig file so
897          * it's an XBSA server. Don't know if its ADSM or not so its unknown.
898          */
899         xbsaType =
900             ((code == 1) ? XBSA_SERVER_TYPE_UNKNOWN : XBSA_SERVER_TYPE_NONE);
901     }
902
903     if (as->parms[6].items) {   /* -restoretofile */
904         restoretofile = strdup(as->parms[6].items->data);
905         printf("Restore to file '%s'\n", restoretofile);
906     }
907
908     /* Go and read the config file: CFG_<device> or CFG_<port>. We will also set
909      * the exact xbsaType within the call (won't be unknown) - double check.
910      */
911     code = GetConfigParams(pFile, portOffset);
912     if (code)
913         exit(code);
914 #ifdef xbsa
915     if (xbsaType == XBSA_SERVER_TYPE_UNKNOWN) {
916         printf
917             ("\nConfiguration file error, the TYPE parameter must be specified, or\n");
918         printf("an entry must exist in %s for port %d\n", tapeConfigFile,
919                portOffset);
920         exit(1);
921     }
922 #else
923     /* Not compiled for XBSA code so we can't support it */
924     if (CONF_XBSA) {
925         printf("\nNo entry found in %s for port %d\n", tapeConfigFile,
926                portOffset);
927         printf("This binary does not have XBSA support\n");
928         exit(1);
929     }
930 #endif
931
932     /* Open the log files. The pathnames were set in GetConfigParams() */
933     logIO = fopen(logFile, "a");
934     if (!logIO) {
935         fprintf(stderr, "Failed to open %s\n", logFile);
936         exit(1);
937     }
938     ErrorlogIO = fopen(ErrorlogFile, "a");
939     if (!ErrorlogIO) {
940         fprintf(stderr, "Failed to open %s\n", ErrorlogFile);
941         exit(1);
942     }
943     if (lastLog) {
944         lastLogIO = fopen(lastLogFile, "a");
945         if (!lastLogIO) {
946             fprintf(stderr, "Failed to open %s\n", lastLogFile);
947             exit(1);
948         }
949     }
950     if (centralLogFile) {
951         struct stat sbuf;
952         afs_int32 statcode;
953 #ifndef AFS_NT40_ENV
954         char *path;
955 #endif
956
957         statcode = stat(centralLogFile, &sbuf);
958         centralLogIO = fopen(centralLogFile, "a");
959         if (!centralLogIO) {
960             fprintf(stderr, "Failed to open %s; error %d\n", centralLogFile,
961                     errno);
962             exit(1);
963         }
964 #ifndef AFS_NT40_ENV
965         /* Make sure it is not in AFS, has to have been created first */
966         path = malloc(AFSDIR_PATH_MAX);
967         if (path == NULL || !realpath(centralLogFile, path)) {
968             fprintf(stderr,
969                     "Warning: can't determine real path of '%s' (%d)\n",
970                     centralLogFile, errno);
971         } else {
972             if (strncmp(path, "/afs/", 5) == 0) {
973                 fprintf(stderr, "The central log '%s' should not be in AFS\n",
974                         centralLogFile);
975                 exit(1);
976             }
977         }
978         free(path);
979 #endif
980
981         /* Write header if created it */
982         if (statcode) {
983             char *h1 =
984                 "TASK   START DATE/TIME      END DATE/TIME        ELAPSED   VOLUMESET\n";
985             char *h2 =
986                 "-----  -------------------  -------------------  --------  ---------\n";
987             /* File didn't exist before so write the header lines */
988             fwrite(h1, strlen(h1), 1, centralLogIO);
989             fwrite(h2, strlen(h2), 1, centralLogIO);
990             fflush(centralLogIO);
991         }
992     }
993
994     /* Open the configuration directory */
995     butc_confdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
996     if (butc_confdir == NULL) {
997         TLog(0, "Failed to open server configuration directory");
998         exit(1);
999     }
1000
1001     /* Start auditing */
1002     osi_audit_init();
1003     /* Process -audit-interface and -auditlog */
1004     if (as->parms[10].items != NULL)
1005         auditIface = as->parms[10].items->data;
1006
1007     if (as->parms[9].items != NULL) {
1008         int code;
1009         code = osi_audit_cmd_Options(auditIface, as->parms[9].items);
1010         if (code) {
1011             TLog(0, "Error processing -audit-interface or -auditlog parameters");
1012             exit(1);
1013         }
1014     }
1015
1016     osi_audit_open();
1017     osi_audit(TC_StartEvent, 0, AUD_END);
1018     osi_audit_set_user_check(butc_confdir, tc_IsLocalRealmMatch);
1019
1020     if (as->parms[1].items) {
1021         debugLevel = SafeATOL(as->parms[1].items->data);
1022         if (debugLevel == -1) {
1023             TLog(0, "Illegal debug level '%s'\n", as->parms[1].items->data);
1024             exit(1);
1025         }
1026     }
1027 #ifdef xbsa
1028     /* Setup XBSA library interface */
1029     if (CONF_XBSA) {
1030         afs_int32 rc;
1031         rc = xbsa_MountLibrary(&butxInfo, xbsaType);
1032         if (rc != XBSA_SUCCESS) {
1033             TapeLog(0, 0, rc, 0, "Unable to mount the XBSA library\n");
1034             return (1);
1035         }
1036
1037         forcemultiple = (as->parms[7].items ? 1 : 0);/*-xbsaforcemultiple */
1038         if (forcemultiple)
1039             printf("Force XBSA multiple server support\n");
1040
1041         rc = InitToServer(0 /*taskid */ , &butxInfo, adsmServerName);
1042         if (rc != XBSA_SUCCESS)
1043             return (1);
1044         (void)signal(SIGINT, xbsa_shutdown);
1045         (void)signal(SIGHUP, xbsa_shutdown);
1046     }
1047 #endif /*xbsa */
1048
1049     /* cell switch */
1050     if (as->parms[2].items)
1051         strncpy(cellName, as->parms[2].items->data, sizeof(cellName));
1052     else
1053         cellName[0] = '\0';
1054
1055     if (as->parms[4].items)
1056         autoQuery = 0;
1057
1058     localauth = (as->parms[5].items ? 1 : 0);
1059     rxBind = (as->parms[8].items ? 1 : 0);
1060     allow_unauth = (as->parms[11].items ? 1 : 0);
1061
1062     if (!allow_unauth && !localauth) {
1063         const char *errstr = "Neither -localauth nor -allow_unauthenticated was provided; refusing to start in unintended insecure configuration\n";
1064         TLog(0, "%s", (char *)errstr);
1065         exit(1);
1066     }
1067
1068     if (rxBind) {
1069         afs_int32 ccode;
1070         if (AFSDIR_SERVER_NETRESTRICT_FILEPATH ||
1071             AFSDIR_SERVER_NETINFO_FILEPATH) {
1072             char reason[1024];
1073             ccode = afsconf_ParseNetFiles(SHostAddrs, NULL, NULL,
1074                                           ADDRSPERSITE, reason,
1075                                           AFSDIR_SERVER_NETINFO_FILEPATH,
1076                                           AFSDIR_SERVER_NETRESTRICT_FILEPATH);
1077         } else
1078         {
1079             ccode = rx_getAllAddr(SHostAddrs, ADDRSPERSITE);
1080         }
1081         if (ccode == 1)
1082             host = SHostAddrs[0];
1083     }
1084
1085     TLog(0, "butc binding rx to %s:%d\n",
1086          afs_inet_ntoa_r(host, hoststr), BC_TAPEPORT + portOffset);
1087     code = rx_InitHost(host, htons(BC_TAPEPORT + portOffset));
1088     if (code) {
1089         TapeLog(0, 0, code, 0, "rx init failed on port %u\n",
1090                 BC_TAPEPORT + portOffset);
1091         exit(1);
1092     }
1093     rx_SetRxDeadTime(150);
1094
1095     /* Establish connection with the vldb server */
1096     code = vldbClientInit(0, localauth, cellName, &cstruct, &tokenExpires);
1097     if (code) {
1098         TapeLog(0, 0, code, 0, "Can't access vldb\n");
1099         return code;
1100     }
1101
1102     strcpy(globalCellName, cellName);
1103
1104     /*initialize the dumpNode list */
1105     InitNodeList(portOffset);
1106
1107     deviceLatch = malloc(sizeof(struct deviceSyncNode));
1108     Lock_Init(&(deviceLatch->lock));
1109     deviceLatch->flags = 0;
1110
1111     /* initialize database support, volume support, and logs */
1112
1113     /*
1114      * Create security objects for the Rx server functionality.  Historically
1115      * this was a single rxnull security object, since the tape controller was
1116      * run by an operator that had local access to the tape device and some
1117      * administrative privilege in the cell (to be able to perform volume-level
1118      * accesses), but on a machine that was not necessarily trusted to hold the
1119      * cell-wide key.
1120      *
1121      * Such a configuration is, of course, insecure because anyone can make
1122      * inbound RPCs and manipulate the database, including creating bogus
1123      * dumps and restoring them!  Additionally, in modern usage, butc is
1124      * frequently run with -localauth to authenticate its outbound connections
1125      * to the volservers and budb with the cell-wide key, in which case the
1126      * cell-wide key is present and could be used to authenticate incoming
1127      * connections as well.
1128      *
1129      * If -localauth is in use, create the full barrage of server security
1130      * objects, including rxkad, so that inbound connections can be verified
1131      * to only be made by authenticated clients.  Otherwise, only the rxnull
1132      * class is in use with a single server security object.  Note that butc
1133      * will refuse to start in this configuration unless the
1134      * "-allow_unauthenticated" flag is provided, indicating that the operator
1135      * has ensured that incoming connections are appropriately restricted by
1136      * firewall configuration or network topology.
1137      */
1138
1139     if (allow_unauth) {
1140         nullObjects[RX_SECIDX_NULL] = rxnull_NewServerSecurityObject();
1141         if (!nullObjects[RX_SECIDX_NULL]) {
1142             TLog(0, "rxnull_NewServerSecurityObject");
1143             exit(1);
1144         }
1145         numClasses = 1;
1146         secObjs = nullObjects;
1147     } else {
1148         /* Must be -localauth, so the cell keys are available. */
1149         struct afsconf_bsso_info bsso;
1150         memset(&bsso, 0, sizeof(bsso));
1151         bsso.dir = butc_confdir;
1152         afsconf_BuildServerSecurityObjects_int(&bsso, &allObjs, &numClasses);
1153         secObjs = allObjs;
1154     }
1155
1156     service =
1157         rx_NewServiceHost(host, 0, 1, "BUTC", secObjs, numClasses, TC_ExecuteRequest);
1158     if (!service) {
1159         TLog(0, "rx_NewService");
1160         exit(1);
1161     }
1162     rx_SetMaxProcs(service, 4);
1163
1164     /* Establish connection to the backup database */
1165     code = udbClientInit(0, localauth, cellName);
1166     if (code) {
1167         TapeLog(0, 0, code, 0, "Can't access backup database\n");
1168         exit(1);
1169     }
1170     /* This call is here to verify that we are authentiated.
1171      * The call does nothing and will return BUDB_NOTPERMITTED
1172      * if we don't belong.
1173      */
1174     code = bcdb_deleteDump(0, 0, 0, 0);
1175     if (code == BUDB_NOTPERMITTED) {
1176         TapeLog(0, 0, code, 0, "Can't access backup database\n");
1177         exit(1);
1178     }
1179
1180     initStatus();
1181 #ifdef AFS_PTHREAD_ENV
1182     code = pthread_attr_init(&tattr);
1183     if (code) {
1184         TapeLog(0, 0, code, 0,
1185                 "Can't pthread_attr_init database monitor task");
1186         exit(1);
1187     }
1188     code = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
1189     if (code) {
1190         TapeLog(0, 0, code, 0,
1191                 "Can't pthread_attr_setdetachstate database monitor task");
1192         exit(1);
1193     }
1194     AFS_SIGSET_CLEAR();
1195     code = pthread_create(&dbWatcherPid, &tattr, dbWatcher, (void *)2);
1196     AFS_SIGSET_RESTORE();
1197 #else
1198     code =
1199         LWP_CreateProcess(dbWatcher, 20480, LWP_NORMAL_PRIORITY, (void *)2,
1200                           "dbWatcher", &dbWatcherPid);
1201 #endif
1202     if (code) {
1203         TapeLog(0, 0, code, 0, "Can't create database monitor task");
1204         exit(1);
1205     }
1206
1207     TLog(0, "Starting Tape Coordinator: Port offset %u   Debug level %u\n",
1208          portOffset, debugLevel);
1209     TLog(0, "Token expires: %s\n", cTIME(&tokenExpires));
1210
1211     rx_StartServer(1);          /* Donate this process to the server process pool */
1212     TLog(0, "Error: StartServer returned");
1213     exit(1);
1214 }
1215
1216 #ifndef AFS_NT40_ENV
1217 #include "AFS_component_version_number.c"
1218 #endif
1219
1220 int
1221 main(int argc, char **argv)
1222 {
1223     struct cmd_syndesc *ts;
1224     struct cmd_item *ti;
1225
1226 #ifdef  AFS_AIX32_ENV
1227     /*
1228      * The following signal action for AIX is necessary so that in case of a
1229      * crash (i.e. core is generated) we can include the user's data section
1230      * in the core dump. Unfortunately, by default, only a partial core is
1231      * generated which, in many cases, isn't too useful.
1232      */
1233     struct sigaction nsa;
1234
1235     sigemptyset(&nsa.sa_mask);
1236     nsa.sa_handler = SIG_DFL;
1237     nsa.sa_flags = SA_FULLDUMP;
1238     sigaction(SIGSEGV, &nsa, NULL);
1239     sigaction(SIGABRT, &nsa, NULL);
1240 #endif
1241
1242     setlinebuf(stdout);
1243
1244     ts = cmd_CreateSyntax(NULL, WorkerBee, NULL, 0, "tape coordinator");
1245     cmd_AddParm(ts, "-port", CMD_SINGLE, CMD_OPTIONAL, "port offset");
1246     cmd_AddParm(ts, "-debuglevel", CMD_SINGLE, CMD_OPTIONAL, "0 | 1 | 2");
1247     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1248     cmd_AddParm(ts, "-device", CMD_SINGLE, (CMD_OPTIONAL | CMD_HIDE),
1249                 "tape device path");
1250     cmd_AddParm(ts, "-noautoquery", CMD_FLAG, CMD_OPTIONAL,
1251                 "do not query operator for first tape");
1252     cmd_AddParm(ts, "-localauth", CMD_FLAG, CMD_OPTIONAL,
1253                 "create tickets from KeyFile");
1254     cmd_AddParm(ts, "-restoretofile", CMD_SINGLE, (CMD_OPTIONAL | CMD_HIDE),
1255                 "file to restore to");
1256     cmd_AddParm(ts, "-xbsaforcemultiple", CMD_FLAG, (CMD_OPTIONAL | CMD_HIDE),
1257                 "Force multiple XBSA server support");
1258     cmd_AddParm(ts, "-rxbind", CMD_FLAG, CMD_OPTIONAL,
1259                 "bind Rx socket");
1260     cmd_AddParm(ts, "-auditlog", CMD_LIST, CMD_OPTIONAL,
1261                 "[interface:]path[:options]");
1262     cmd_AddParm(ts, "-audit-interface", CMD_SINGLE, CMD_OPTIONAL,
1263                 "default interface");
1264     cmd_AddParm(ts, "-allow_unauthenticated", CMD_FLAG, CMD_OPTIONAL,
1265                 "allow unauthenticated inbound RPCs (requires firewalling)");
1266
1267     /* Initialize dirpaths */
1268     if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) {
1269 #ifdef AFS_NT40_ENV
1270         ReportErrorEventAlt(AFSEVT_SVR_NO_INSTALL_DIR, 0, argv[0], 0);
1271 #endif
1272         fprintf(stderr, "Unable to obtain AFS server directory.\n");
1273         exit(2);
1274     }
1275
1276     /* setup the file paths */
1277     strcompose(eFile, AFSDIR_PATH_MAX, AFSDIR_SERVER_BACKUP_DIRPATH, "/",
1278                TE_PREFIX, (char *)NULL);
1279     strcompose(lFile, AFSDIR_PATH_MAX, AFSDIR_SERVER_BACKUP_DIRPATH, "/",
1280                TL_PREFIX, (char *)NULL);
1281     strcompose(pFile, AFSDIR_PATH_MAX, AFSDIR_SERVER_BACKUP_DIRPATH, "/",
1282                CFG_PREFIX, (char *)NULL);
1283     strcpy(tapeConfigFile, AFSDIR_SERVER_TAPECONFIG_FILEPATH);
1284
1285     /* special case "no args" case since cmd_dispatch gives help message
1286      * instead
1287      */
1288     if (argc == 1) {
1289         ts = calloc(1, sizeof(struct cmd_syndesc));
1290
1291         ti = malloc(sizeof(struct cmd_item));
1292         ti->next = 0;
1293         ti->data = "0";
1294         ts->parms[0].items = ti;
1295         ti = malloc(sizeof(struct cmd_item));
1296         ti->next = 0;
1297         ti->data = "0";
1298         ts->parms[1].items = ti;
1299         ts->parms[2].items = NULL;
1300         ts->parms[3].items = NULL;
1301         ts->parms[4].items = NULL;
1302         ts->parms[5].items = NULL;
1303         return WorkerBee(ts, NULL);
1304     } else
1305         return cmd_Dispatch(argc, argv);
1306 }