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