Import Upstream version 1.8.5
[hcoop/debian/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[256];
73 char ErrorlogFile[256];
74 char lastLogFile[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[256];
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 sprintf(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 sprintf(logFile, "%s_%d", lFile, port);
445 sprintf(lastLogFile, "%s_%d.lp", lFile, port);
446 sprintf(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 afs_uint32 host = htonl(INADDR_ANY);
863 char *auditFileName = NULL;
864 char *auditInterface = NULL;
865
866 debugLevel = 0;
867
868 /*initialize the error tables */
869 initialize_KA_error_table();
870 initialize_RXK_error_table();
871 initialize_KTC_error_table();
872 initialize_ACFG_error_table();
873 initialize_CMD_error_table();
874 initialize_VL_error_table();
875 initialize_BUTM_error_table();
876 initialize_BUTC_error_table();
877 #ifdef xbsa
878 initialize_BUTX_error_table();
879 #endif /*xbs */
880 initialize_VOLS_error_table();
881 initialize_BUDB_error_table();
882 initialize_BUCD_error_table();
883
884 if (as->parms[0].items) {
885 portOffset = SafeATOL(as->parms[0].items->data);
886 if (portOffset == -1) {
887 fprintf(stderr, "Illegal port offset '%s'\n",
888 as->parms[0].items->data);
889 exit(1);
890 } else if (portOffset > BC_MAXPORTOFFSET) {
891 fprintf(stderr, "%u exceeds max port offset %u\n", portOffset,
892 BC_MAXPORTOFFSET);
893 exit(1);
894 }
895 }
896
897 xbsaType = XBSA_SERVER_TYPE_NONE; /* default */
898 if (as->parms[3].items) { /* -device */
899 globalTapeConfig.capacity = 0x7fffffff; /* 2T for max tape capacity */
900 globalTapeConfig.fileMarkSize = 0;
901 globalTapeConfig.portOffset = portOffset;
902 strncpy(globalTapeConfig.device, as->parms[3].items->data, 100);
903 xbsaType = XBSA_SERVER_TYPE_NONE; /* Not XBSA */
904 } else {
905 /* Search for an entry in tapeconfig file */
906 code = GetDeviceConfig(tapeConfigFile, &globalTapeConfig, portOffset);
907 if (code == -1) {
908 fprintf(stderr, "Problem in reading config file %s\n",
909 tapeConfigFile);
910 exit(1);
911 }
912 /* Set xbsaType. If code == 1, no entry was found in the tapeconfig file so
913 * it's an XBSA server. Don't know if its ADSM or not so its unknown.
914 */
915 xbsaType =
916 ((code == 1) ? XBSA_SERVER_TYPE_UNKNOWN : XBSA_SERVER_TYPE_NONE);
917 }
918
919 if (as->parms[6].items) { /* -restoretofile */
920 restoretofile = strdup(as->parms[6].items->data);
921 printf("Restore to file '%s'\n", restoretofile);
922 }
923
924 /* Go and read the config file: CFG_<device> or CFG_<port>. We will also set
925 * the exact xbsaType within the call (won't be unknown) - double check.
926 */
927 code = GetConfigParams(pFile, portOffset);
928 if (code)
929 exit(code);
930 #ifdef xbsa
931 if (xbsaType == XBSA_SERVER_TYPE_UNKNOWN) {
932 printf
933 ("\nConfiguration file error, the TYPE parameter must be specified, or\n");
934 printf("an entry must exist in %s for port %d\n", tapeConfigFile,
935 portOffset);
936 exit(1);
937 }
938 #else
939 /* Not compiled for XBSA code so we can't support it */
940 if (CONF_XBSA) {
941 printf("\nNo entry found in %s for port %d\n", tapeConfigFile,
942 portOffset);
943 printf("This binary does not have XBSA support\n");
944 exit(1);
945 }
946 #endif
947
948 /* Open the log files. The pathnames were set in GetConfigParams() */
949 logIO = fopen(logFile, "a");
950 if (!logIO) {
951 fprintf(stderr, "Failed to open %s\n", logFile);
952 exit(1);
953 }
954 ErrorlogIO = fopen(ErrorlogFile, "a");
955 if (!ErrorlogIO) {
956 fprintf(stderr, "Failed to open %s\n", ErrorlogFile);
957 exit(1);
958 }
959 if (lastLog) {
960 lastLogIO = fopen(lastLogFile, "a");
961 if (!lastLogIO) {
962 fprintf(stderr, "Failed to open %s\n", lastLogFile);
963 exit(1);
964 }
965 }
966 if (centralLogFile) {
967 struct stat sbuf;
968 afs_int32 statcode;
969 #ifndef AFS_NT40_ENV
970 char *path;
971 #endif
972
973 statcode = stat(centralLogFile, &sbuf);
974 centralLogIO = fopen(centralLogFile, "a");
975 if (!centralLogIO) {
976 fprintf(stderr, "Failed to open %s; error %d\n", centralLogFile,
977 errno);
978 exit(1);
979 }
980 #ifndef AFS_NT40_ENV
981 /* Make sure it is not in AFS, has to have been created first */
982 path = malloc(AFSDIR_PATH_MAX);
983 if (path == NULL || !realpath(centralLogFile, path)) {
984 fprintf(stderr,
985 "Warning: can't determine real path of '%s' (%d)\n",
986 centralLogFile, errno);
987 } else {
988 if (strncmp(path, "/afs/", 5) == 0) {
989 fprintf(stderr, "The central log '%s' should not be in AFS\n",
990 centralLogFile);
991 exit(1);
992 }
993 }
994 free(path);
995 #endif
996
997 /* Write header if created it */
998 if (statcode) {
999 char *h1 =
1000 "TASK START DATE/TIME END DATE/TIME ELAPSED VOLUMESET\n";
1001 char *h2 =
1002 "----- ------------------- ------------------- -------- ---------\n";
1003 /* File didn't exist before so write the header lines */
1004 fwrite(h1, strlen(h1), 1, centralLogIO);
1005 fwrite(h2, strlen(h2), 1, centralLogIO);
1006 fflush(centralLogIO);
1007 }
1008 }
1009
1010 /* Open the configuration directory */
1011 butc_confdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
1012 if (butc_confdir == NULL) {
1013 TLog(0, "Failed to open server configuration directory");
1014 exit(1);
1015 }
1016
1017 /* Start auditing */
1018 osi_audit_init();
1019 if (as->parms[9].items) {
1020 auditFileName = as->parms[9].items->data;
1021 }
1022 if (auditFileName != NULL)
1023 osi_audit_file(auditFileName);
1024 if (as->parms[10].items) {
1025 auditInterface = as->parms[10].items->data;
1026 if (osi_audit_interface(auditInterface)) {
1027 TLog(0, "Invalid audit interface '%s'\n", auditInterface);
1028 exit(1);
1029 }
1030 }
1031 osi_audit(TC_StartEvent, 0, AUD_END);
1032 osi_audit_set_user_check(butc_confdir, tc_IsLocalRealmMatch);
1033
1034 if (as->parms[1].items) {
1035 debugLevel = SafeATOL(as->parms[1].items->data);
1036 if (debugLevel == -1) {
1037 TLog(0, "Illegal debug level '%s'\n", as->parms[1].items->data);
1038 exit(1);
1039 }
1040 }
1041 #ifdef xbsa
1042 /* Setup XBSA library interface */
1043 if (CONF_XBSA) {
1044 afs_int32 rc;
1045 rc = xbsa_MountLibrary(&butxInfo, xbsaType);
1046 if (rc != XBSA_SUCCESS) {
1047 TapeLog(0, 0, rc, 0, "Unable to mount the XBSA library\n");
1048 return (1);
1049 }
1050
1051 forcemultiple = (as->parms[7].items ? 1 : 0);/*-xbsaforcemultiple */
1052 if (forcemultiple)
1053 printf("Force XBSA multiple server support\n");
1054
1055 rc = InitToServer(0 /*taskid */ , &butxInfo, adsmServerName);
1056 if (rc != XBSA_SUCCESS)
1057 return (1);
1058 (void)signal(SIGINT, xbsa_shutdown);
1059 (void)signal(SIGHUP, xbsa_shutdown);
1060 }
1061 #endif /*xbsa */
1062
1063 /* cell switch */
1064 if (as->parms[2].items)
1065 strncpy(cellName, as->parms[2].items->data, sizeof(cellName));
1066 else
1067 cellName[0] = '\0';
1068
1069 if (as->parms[4].items)
1070 autoQuery = 0;
1071
1072 localauth = (as->parms[5].items ? 1 : 0);
1073 rxBind = (as->parms[8].items ? 1 : 0);
1074 allow_unauth = (as->parms[11].items ? 1 : 0);
1075
1076 if (!allow_unauth && !localauth) {
1077 const char *errstr = "Neither -localauth nor -allow_unauthenticated was provided; refusing to start in unintended insecure configuration\n";
1078 TLog(0, "%s", (char *)errstr);
1079 exit(1);
1080 }
1081
1082 if (rxBind) {
1083 afs_int32 ccode;
1084 if (AFSDIR_SERVER_NETRESTRICT_FILEPATH ||
1085 AFSDIR_SERVER_NETINFO_FILEPATH) {
1086 char reason[1024];
1087 ccode = afsconf_ParseNetFiles(SHostAddrs, NULL, NULL,
1088 ADDRSPERSITE, reason,
1089 AFSDIR_SERVER_NETINFO_FILEPATH,
1090 AFSDIR_SERVER_NETRESTRICT_FILEPATH);
1091 } else
1092 {
1093 ccode = rx_getAllAddr(SHostAddrs, ADDRSPERSITE);
1094 }
1095 if (ccode == 1)
1096 host = SHostAddrs[0];
1097 }
1098
1099 code = rx_InitHost(host, htons(BC_TAPEPORT + portOffset));
1100 if (code) {
1101 TapeLog(0, 0, code, 0, "rx init failed on port %u\n",
1102 BC_TAPEPORT + portOffset);
1103 exit(1);
1104 }
1105 rx_SetRxDeadTime(150);
1106
1107 /* Establish connection with the vldb server */
1108 code = vldbClientInit(0, localauth, cellName, &cstruct, &tokenExpires);
1109 if (code) {
1110 TapeLog(0, 0, code, 0, "Can't access vldb\n");
1111 return code;
1112 }
1113
1114 strcpy(globalCellName, cellName);
1115
1116 /*initialize the dumpNode list */
1117 InitNodeList(portOffset);
1118
1119 deviceLatch = malloc(sizeof(struct deviceSyncNode));
1120 Lock_Init(&(deviceLatch->lock));
1121 deviceLatch->flags = 0;
1122
1123 /* initialize database support, volume support, and logs */
1124
1125 /*
1126 * Create security objects for the Rx server functionality. Historically
1127 * this was a single rxnull security object, since the tape controller was
1128 * run by an operator that had local access to the tape device and some
1129 * administrative privilege in the cell (to be able to perform volume-level
1130 * accesses), but on a machine that was not necessarily trusted to hold the
1131 * cell-wide key.
1132 *
1133 * Such a configuration is, of course, insecure because anyone can make
1134 * inbound RPCs and manipulate the database, including creating bogus
1135 * dumps and restoring them! Additionally, in modern usage, butc is
1136 * frequently run with -localauth to authenticate its outbound connections
1137 * to the volservers and budb with the cell-wide key, in which case the
1138 * cell-wide key is present and could be used to authenticate incoming
1139 * connections as well.
1140 *
1141 * If -localauth is in use, create the full barrage of server security
1142 * objects, including rxkad, so that inbound connections can be verified
1143 * to only be made by authenticated clients. Otherwise, only the rxnull
1144 * class is in use with a single server security object. Note that butc
1145 * will refuse to start in this configuration unless the
1146 * "-allow_unauthenticated" flag is provided, indicating that the operator
1147 * has ensured that incoming connections are appropriately restricted by
1148 * firewall configuration or network topology.
1149 */
1150
1151 if (allow_unauth) {
1152 nullObjects[RX_SECIDX_NULL] = rxnull_NewServerSecurityObject();
1153 if (!nullObjects[RX_SECIDX_NULL]) {
1154 TLog(0, "rxnull_NewServerSecurityObject");
1155 exit(1);
1156 }
1157 numClasses = 1;
1158 secObjs = nullObjects;
1159 } else {
1160 /* Must be -localauth, so the cell keys are available. */
1161 afsconf_BuildServerSecurityObjects(butc_confdir, &allObjs, &numClasses);
1162 secObjs = allObjs;
1163 }
1164
1165 service =
1166 rx_NewServiceHost(host, 0, 1, "BUTC", secObjs, numClasses, TC_ExecuteRequest);
1167 if (!service) {
1168 TLog(0, "rx_NewService");
1169 exit(1);
1170 }
1171 rx_SetMaxProcs(service, 4);
1172
1173 /* Establish connection to the backup database */
1174 code = udbClientInit(0, localauth, cellName);
1175 if (code) {
1176 TapeLog(0, 0, code, 0, "Can't access backup database\n");
1177 exit(1);
1178 }
1179 /* This call is here to verify that we are authentiated.
1180 * The call does nothing and will return BUDB_NOTPERMITTED
1181 * if we don't belong.
1182 */
1183 code = bcdb_deleteDump(0, 0, 0, 0);
1184 if (code == BUDB_NOTPERMITTED) {
1185 TapeLog(0, 0, code, 0, "Can't access backup database\n");
1186 exit(1);
1187 }
1188
1189 initStatus();
1190 #ifdef AFS_PTHREAD_ENV
1191 code = pthread_attr_init(&tattr);
1192 if (code) {
1193 TapeLog(0, 0, code, 0,
1194 "Can't pthread_attr_init database monitor task");
1195 exit(1);
1196 }
1197 code = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
1198 if (code) {
1199 TapeLog(0, 0, code, 0,
1200 "Can't pthread_attr_setdetachstate database monitor task");
1201 exit(1);
1202 }
1203 AFS_SIGSET_CLEAR();
1204 code = pthread_create(&dbWatcherPid, &tattr, dbWatcher, (void *)2);
1205 AFS_SIGSET_RESTORE();
1206 #else
1207 code =
1208 LWP_CreateProcess(dbWatcher, 20480, LWP_NORMAL_PRIORITY, (void *)2,
1209 "dbWatcher", &dbWatcherPid);
1210 #endif
1211 if (code) {
1212 TapeLog(0, 0, code, 0, "Can't create database monitor task");
1213 exit(1);
1214 }
1215
1216 TLog(0, "Starting Tape Coordinator: Port offset %u Debug level %u\n",
1217 portOffset, debugLevel);
1218 TLog(0, "Token expires: %s\n", cTIME(&tokenExpires));
1219
1220 rx_StartServer(1); /* Donate this process to the server process pool */
1221 TLog(0, "Error: StartServer returned");
1222 exit(1);
1223 }
1224
1225 #ifndef AFS_NT40_ENV
1226 #include "AFS_component_version_number.c"
1227 #endif
1228
1229 int
1230 main(int argc, char **argv)
1231 {
1232 struct cmd_syndesc *ts;
1233 struct cmd_item *ti;
1234
1235 #ifdef AFS_AIX32_ENV
1236 /*
1237 * The following signal action for AIX is necessary so that in case of a
1238 * crash (i.e. core is generated) we can include the user's data section
1239 * in the core dump. Unfortunately, by default, only a partial core is
1240 * generated which, in many cases, isn't too useful.
1241 */
1242 struct sigaction nsa;
1243
1244 sigemptyset(&nsa.sa_mask);
1245 nsa.sa_handler = SIG_DFL;
1246 nsa.sa_flags = SA_FULLDUMP;
1247 sigaction(SIGSEGV, &nsa, NULL);
1248 sigaction(SIGABRT, &nsa, NULL);
1249 #endif
1250
1251 setlinebuf(stdout);
1252
1253 ts = cmd_CreateSyntax(NULL, WorkerBee, NULL, 0, "tape coordinator");
1254 cmd_AddParm(ts, "-port", CMD_SINGLE, CMD_OPTIONAL, "port offset");
1255 cmd_AddParm(ts, "-debuglevel", CMD_SINGLE, CMD_OPTIONAL, "0 | 1 | 2");
1256 cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1257 cmd_AddParm(ts, "-device", CMD_SINGLE, (CMD_OPTIONAL | CMD_HIDE),
1258 "tape device path");
1259 cmd_AddParm(ts, "-noautoquery", CMD_FLAG, CMD_OPTIONAL,
1260 "do not query operator for first tape");
1261 cmd_AddParm(ts, "-localauth", CMD_FLAG, CMD_OPTIONAL,
1262 "create tickets from KeyFile");
1263 cmd_AddParm(ts, "-restoretofile", CMD_SINGLE, (CMD_OPTIONAL | CMD_HIDE),
1264 "file to restore to");
1265 cmd_AddParm(ts, "-xbsaforcemultiple", CMD_FLAG, (CMD_OPTIONAL | CMD_HIDE),
1266 "Force multiple XBSA server support");
1267 cmd_AddParm(ts, "-rxbind", CMD_FLAG, CMD_OPTIONAL,
1268 "bind Rx socket");
1269 cmd_AddParm(ts, "-auditlog", CMD_SINGLE, CMD_OPTIONAL, "location of audit log");
1270 cmd_AddParm(ts, "-audit-interface", CMD_SINGLE, CMD_OPTIONAL,
1271 "interface to use for audit logging");
1272 cmd_AddParm(ts, "-allow_unauthenticated", CMD_FLAG, CMD_OPTIONAL,
1273 "allow unauthenticated inbound RPCs (requires firewalling)");
1274
1275 /* Initialize dirpaths */
1276 if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) {
1277 #ifdef AFS_NT40_ENV
1278 ReportErrorEventAlt(AFSEVT_SVR_NO_INSTALL_DIR, 0, argv[0], 0);
1279 #endif
1280 fprintf(stderr, "Unable to obtain AFS server directory.\n");
1281 exit(2);
1282 }
1283
1284 /* setup the file paths */
1285 strcompose(eFile, AFSDIR_PATH_MAX, AFSDIR_SERVER_BACKUP_DIRPATH, "/",
1286 TE_PREFIX, (char *)NULL);
1287 strcompose(lFile, AFSDIR_PATH_MAX, AFSDIR_SERVER_BACKUP_DIRPATH, "/",
1288 TL_PREFIX, (char *)NULL);
1289 strcompose(pFile, AFSDIR_PATH_MAX, AFSDIR_SERVER_BACKUP_DIRPATH, "/",
1290 CFG_PREFIX, (char *)NULL);
1291 strcpy(tapeConfigFile, AFSDIR_SERVER_TAPECONFIG_FILEPATH);
1292
1293 /* special case "no args" case since cmd_dispatch gives help message
1294 * instead
1295 */
1296 if (argc == 1) {
1297 ts = calloc(1, sizeof(struct cmd_syndesc));
1298
1299 ti = malloc(sizeof(struct cmd_item));
1300 ti->next = 0;
1301 ti->data = "0";
1302 ts->parms[0].items = ti;
1303 ti = malloc(sizeof(struct cmd_item));
1304 ti->next = 0;
1305 ti->data = "0";
1306 ts->parms[1].items = ti;
1307 ts->parms[2].items = NULL;
1308 ts->parms[3].items = NULL;
1309 ts->parms[4].items = NULL;
1310 ts->parms[5].items = NULL;
1311 return WorkerBee(ts, NULL);
1312 } else
1313 return cmd_Dispatch(argc, argv);
1314 }