OPENAFS-SA-2018-001 backup: use authenticated connection to butc
[openafs.git] / src / bucoord / dump.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 /*
11  * ALL RIGHTS RESERVED
12  */
13
14 #include <afsconfig.h>
15 #include <afs/param.h>
16
17 #include <roken.h>
18
19 #include <afs/cmd.h>
20 #include <afs/cellconfig.h>
21 #include <lwp.h>
22 #include <rx/rx.h>
23 #include <afs/bubasics.h>
24 #include <afs/butc.h>
25 #include <afs/com_err.h>
26 #include <lock.h>               /* for checking TC_ABORTFAILED. PA */
27 #include <afs/tcdata.h>         /* for checking TC_ABORTFAILED. PA */
28 #include <afs/butc.h>
29
30 #include "bc.h"
31 #include "error_macros.h"
32 #include "bucoord_internal.h"
33 #include "bucoord_prototypes.h"
34
35 struct bc_dumpTask bc_dumpTasks[BC_MAXSIMDUMPS];
36
37 extern char *whoami;
38
39 extern afs_int32 lastTaskCode;
40
41 #define HOSTADDR(sockaddr) (sockaddr)->sin_addr.s_addr
42
43 /* bc_Dumper
44  *      called (indirectly) to make a dump
45  * entry:
46  *      aindex - index into dumpTask array, contains all the information
47  *               relevant to the dump
48  */
49 int
50 bc_Dumper(int aindex)
51 {
52     struct rx_connection *tconn;
53     struct bc_volumeDump *tde;
54     afs_int32 count, port;
55     struct tc_dumpDesc *volDesc = NULL;
56     struct tc_dumpArray volArray;
57     char *baseNamePtr;
58     statusP statusPtr;
59
60     struct tc_dumpInterface dumpInterface;
61     struct tc_dumpInterface *tcdiPtr = &dumpInterface;
62     struct bc_dumpTask *dumpTaskPtr;
63
64     afs_int32 code = 0;
65
66     dumpTaskPtr = &bc_dumpTasks[aindex];
67
68     if (!dumpTaskPtr->portOffset || (dumpTaskPtr->portCount == 0))
69         port = 0;
70     else
71         port = dumpTaskPtr->portOffset[0];
72
73     code = ConnectButc(dumpTaskPtr->config, port, &tconn);
74     if (code)
75         return (code);
76
77     /* count number of volumes to be dumped and
78      * build array of volumes to be sent to backup system
79      */
80     for (count = 0, tde = dumpTaskPtr->volumes; tde;
81          tde = tde->next, count++);
82
83     /* Nothing to dump, so just return success */
84     if (count == 0)
85         goto error_exit;
86
87     volDesc = malloc(count * sizeof(struct tc_dumpDesc));
88     if (!volDesc) {
89         afs_com_err(whoami, BC_NOMEM, NULL);
90         ERROR(BC_NOMEM);
91     }
92
93     for (count = 0, tde = dumpTaskPtr->volumes; tde; tde = tde->next, count++) {
94         strcpy(volDesc[count].name, tde->name);
95         volDesc[count].vid = tde->vid;
96         volDesc[count].vtype = tde->volType;
97         volDesc[count].partition = tde->partition;
98         volDesc[count].hostAddr = HOSTADDR(&tde->server);       /* the internet address */
99         volDesc[count].date = tde->date;
100         volDesc[count].cloneDate = tde->cloneDate;      /* Not yet known */
101     }
102
103     volArray.tc_dumpArray_len = count;  /* element count */
104     volArray.tc_dumpArray_val = volDesc;        /* and data */
105
106     baseNamePtr = tailCompPtr(dumpTaskPtr->dumpName);
107
108     /* setup the interface structure */
109     memset(tcdiPtr, 0, sizeof(*tcdiPtr));
110
111     /* general */
112     strcpy(tcdiPtr->dumpPath, dumpTaskPtr->dumpName);
113     strcpy(tcdiPtr->volumeSetName, dumpTaskPtr->volSetName);
114
115     /* tapeset */
116     strcpy(tcdiPtr->tapeSet.format, dumpTaskPtr->volSetName);
117     strcat(tcdiPtr->tapeSet.format, ".");
118     strcat(tcdiPtr->tapeSet.format, baseNamePtr);
119     strcat(tcdiPtr->tapeSet.format, ".%d");
120     tcdiPtr->tapeSet.a = 1;
121     tcdiPtr->tapeSet.b = 1;
122     tcdiPtr->tapeSet.maxTapes = 1000000000;
123     tcdiPtr->tapeSet.expDate = dumpTaskPtr->expDate;    /* PA */
124     tcdiPtr->tapeSet.expType = dumpTaskPtr->expType;
125
126     /* construct dump set name */
127     strcpy(tcdiPtr->dumpName, dumpTaskPtr->volSetName);
128     strcat(tcdiPtr->dumpName, ".");
129     strcat(tcdiPtr->dumpName, baseNamePtr);
130
131     tcdiPtr->parentDumpId = dumpTaskPtr->parentDumpID;
132     tcdiPtr->dumpLevel = dumpTaskPtr->dumpLevel;
133     tcdiPtr->doAppend = dumpTaskPtr->doAppend;
134
135     /* start the dump on the tape coordinator */
136     printf("Starting dump\n");
137     code = TC_PerformDump(tconn, tcdiPtr, &volArray, &dumpTaskPtr->dumpID);
138     if (code) {
139         afs_com_err(whoami, code, "; Failed to start dump");
140         ERROR(code);
141     }
142
143     afs_com_err(whoami, 0, "Task %u: Dump (%s)", dumpTaskPtr->dumpID,
144             tcdiPtr->dumpName);
145
146     /* create status monitor block */
147     statusPtr = createStatusNode();
148     lock_Status();
149     statusPtr->taskId = dumpTaskPtr->dumpID;
150     statusPtr->port = port;
151     statusPtr->jobNumber = bc_jobNumber();
152     statusPtr->volsTotal = volArray.tc_dumpArray_len;
153     statusPtr->flags &= ~STARTING;
154     sprintf(statusPtr->taskName, "Dump (%s.%s)", dumpTaskPtr->volSetName,
155             baseNamePtr);
156     unlock_Status();
157
158   error_exit:
159     /* locally allocated resources */
160     if (volDesc)
161         free(volDesc);
162
163     if (tconn)
164         rx_DestroyConnection(tconn);
165
166     return (code);
167 }
168
169 /* freeDumpTaskVolumeList
170  *      free the list of volumes used for dumps
171  */
172
173 void
174 freeDumpTaskVolumeList(struct bc_volumeDump *vdptr)
175 {
176     struct bc_volumeDump *nextVdPtr;
177
178     while (vdptr != 0) {
179         nextVdPtr = vdptr->next;
180
181         if (vdptr->name)
182             free(vdptr->name);
183         free(vdptr);
184
185         vdptr = nextVdPtr;
186     }
187 }
188
189 /* bc_DmpRstStart
190  *     The other half of the dump/restore create process call. In bc_StartDmpRst,
191  *     we allocated a dumpTask entry. Here we do the task and then free the entry.
192  */
193 void *
194 bc_DmpRstStart(void *param)
195 {
196     afs_int32 aindex = (intptr_t)param;
197     struct bc_dumpTask *tdump;
198     afs_int32 code;
199
200     tdump = &bc_dumpTasks[aindex];
201
202     code = (tdump->callProc) (aindex);
203     if (code)
204         lastTaskCode = code;
205
206     /* Cleanup allocated data structures */
207     freeDumpTaskVolumeList(tdump->volumes);
208     tdump->dumpID = 0;
209     if (tdump->dumpName)
210         free(tdump->dumpName);
211     if (tdump->newExt)
212         free(tdump->newExt);
213     if (tdump->volSetName)
214         free(tdump->volSetName);
215     if (tdump->portOffset)
216         free(tdump->portOffset);
217     tdump->flags &= ~BC_DI_INUSE;
218
219     return (void *)(intptr_t)code;
220 }
221
222 /* bc_StartDmpRst
223  *      function to start dump running. Packages the relevant information
224  *      (from params) into any free dumpTask structure (globally allocated),
225  *      and then invokes bc_DmpRstStart to do the work, passing it a single
226  *      parameter, the index into the dumpTask array.
227  *
228  * entry:
229  *      aconfig - normally is bc_globalConfig
230  *      aproc - bc_Dumper for doing dumps
231  *              bc_Restorer for doing restores
232  */
233
234 int
235 bc_StartDmpRst(struct bc_config *aconfig, char *adname, char *avname,
236                struct bc_volumeDump *avolsToDump,
237                struct sockaddr_in *adestServer,
238                afs_int32 adestPartition, afs_int32 afromDate, char *anewExt,
239                int aoldFlag, afs_int32 aparent, afs_int32 alevel,
240                int (*aproc) (int), afs_int32 *ports, afs_int32 portCount,
241                struct bc_dumpSchedule *dsptr, int append, int dontExecute)
242 {
243     int i;
244     afs_int32 code;
245     PROCESS junk;
246
247     for (i = 0; i < BC_MAXSIMDUMPS; i++)
248         if (!(bc_dumpTasks[i].flags & BC_DI_INUSE))
249             break;
250
251     if (i >= BC_MAXSIMDUMPS) {
252         afs_com_err(whoami, BC_NOTLOCKED,
253                 "All of the dump/restore slots are in use, try again later");
254         return (BC_NOTLOCKED);
255     }
256
257     memset(&bc_dumpTasks[i], 0, sizeof(struct bc_dumpTask));
258     bc_dumpTasks[i].callProc = aproc;
259     bc_dumpTasks[i].config = aconfig;
260     bc_dumpTasks[i].volumes = avolsToDump;
261     bc_dumpTasks[i].flags = BC_DI_INUSE;
262     bc_dumpTasks[i].dumpName = bc_CopyString(adname);
263     bc_dumpTasks[i].volSetName = bc_CopyString(avname);
264     bc_dumpTasks[i].newExt = bc_CopyString(anewExt);
265     bc_dumpTasks[i].dumpLevel = alevel;
266     bc_dumpTasks[i].parentDumpID = aparent;
267     bc_dumpTasks[i].oldFlag = aoldFlag;
268     bc_dumpTasks[i].fromDate = afromDate;
269     bc_dumpTasks[i].destPartition = adestPartition;
270     bc_dumpTasks[i].portOffset = ports;
271     bc_dumpTasks[i].portCount = portCount;
272     bc_dumpTasks[i].doAppend = append;
273     bc_dumpTasks[i].dontExecute = dontExecute;
274
275     if (dsptr) {
276         /* This should be specified for dumps, but will be 0 for restores */
277         bc_dumpTasks[i].expDate = dsptr->expDate;
278         bc_dumpTasks[i].expType = dsptr->expType;
279     }
280     if (adestServer)
281         memcpy(&bc_dumpTasks[i].destServer, adestServer,
282                sizeof(struct sockaddr_in));
283     else
284         memset(&bc_dumpTasks[i].destServer, 0, sizeof(struct sockaddr_in));
285
286     code =
287         LWP_CreateProcess(bc_DmpRstStart, 20480, LWP_NORMAL_PRIORITY,
288                           (void *)(intptr_t)i, "helper", &junk);
289     if (code) {
290         bc_HandleMisc(code);
291         afs_com_err(whoami, code, "; Can't start thread");
292
293         /* Cleanup allocated data structures */
294         freeDumpTaskVolumeList(bc_dumpTasks[i].volumes);
295         bc_dumpTasks[i].dumpID = 0;
296         if (bc_dumpTasks[i].dumpName)
297             free(bc_dumpTasks[i].dumpName);
298         if (bc_dumpTasks[i].newExt)
299             free(bc_dumpTasks[i].newExt);
300         if (bc_dumpTasks[i].volSetName)
301             free(bc_dumpTasks[i].volSetName);
302         if (bc_dumpTasks[i].portOffset)
303             free(bc_dumpTasks[i].portOffset);
304         bc_dumpTasks[i].flags &= ~BC_DI_INUSE;
305         return (code);
306     }
307
308     return 0;
309 }
310
311 #ifdef notdef
312 /* bc_FindDumpSlot
313  *      Returns the dump slot of the dump with dumpID
314  * entry:
315  *      dumpID - id to look for
316  *      port - portoffset for tape coordinator
317  * exit:
318  *      0-n - i.e. 0 or positive number, is the dump slot
319  *      -1 - failed to find dumpID
320  */
321
322 afs_int32
323 bc_FindDumpSlot(afs_int32 dumpID, afs_int32 port)
324 {
325     int i;
326
327     for (i = 0; i < BC_MAXSIMDUMPS; i++) {
328         if ((bc_dumpTasks[i].flags & BC_DI_INUSE)
329             && (bc_dumpTasks[i].dumpID == dumpID)
330             && ((afs_int32) bc_dumpTasks[i].portOffset == port)) {
331             return (i);
332         }
333     }
334     return (-1);
335 }
336 #endif
337
338 /* bc_LabelTape
339  *      opens a connection to the tape coordinator and requests that it
340  *      label a tape
341  */
342
343 int
344 bc_LabelTape(char *afsname, char *pname, afs_int32 size,
345              struct bc_config *config, afs_int32 port)
346 {
347     struct rx_connection *tconn;
348     afs_int32 code = 0;
349     struct tc_tapeLabel label;
350     statusP statusPtr;
351     afs_uint32 taskId;
352
353     code = ConnectButc(config, port, &tconn);
354     if (code)
355         return (code);
356
357     memset(&label, 0, sizeof(label));
358     if (afsname)
359         strcpy(label.afsname, afsname);
360     if (pname)
361         strcpy(label.pname, (strcmp(pname, "") ? pname : "<NULL>"));
362     label.size = size;
363
364     code = TC_LabelTape(tconn, &label, &taskId);
365     if (code) {
366         afs_com_err(whoami, code, "; Failed to start labeltape");
367         return (code);
368     }
369
370     /* create status monitor block */
371     statusPtr = createStatusNode();
372     lock_Status();
373     statusPtr->taskId = taskId;
374     statusPtr->port = port;
375     statusPtr->jobNumber = bc_jobNumber();
376     /* statusPtr->flags    |= SILENT; *//* don't report termination */
377     statusPtr->flags &= ~STARTING;      /* ok to examine */
378
379     sprintf(statusPtr->taskName, "Labeltape (%s)",
380             (pname ? pname : (afsname ? afsname : "<NULL>")));
381     unlock_Status();
382
383     return 0;
384 }
385
386 /* bc_ReadLabel
387  *      open a connection to the tape coordinator and read the label on
388  *      a tape
389  */
390
391 int
392 bc_ReadLabel(struct bc_config *config, afs_int32 port)
393 {
394     struct rx_connection *tconn;
395     struct tc_tapeLabel label;
396     afs_uint32 taskId;
397     afs_int32 code = 0;
398     char *tname = 0;
399
400     code = ConnectButc(config, port, &tconn);
401     if (code)
402         return (code);
403
404     memset(&label, 0, sizeof(label));
405     code = TC_ReadLabel(tconn, &label, &taskId);
406     if (code) {
407         if (code == BUTM_NOLABEL) {
408             printf("Tape read was unlabelled\n");
409             return 0;
410         }
411         afs_com_err(whoami, code, "; Failed to start readlabel");
412         return (code);
413     }
414
415     if (strcmp(label.pname, ""))
416         tname = label.pname;
417     else if (strcmp(label.afsname, ""))
418         tname = label.afsname;
419
420     if (!tname) {
421         printf("Tape read was labelled : <NULL>  size : %u\n", label.size);
422     } else if (!label.tapeId) {
423         printf("Tape read was labelled : %s size : %lu Kbytes\n", tname,
424                (long unsigned int) label.size);
425     } else {
426         printf("Tape read was labelled : %s (%lu) size : %lu Kbytes\n", tname,
427                (long unsigned int) label.tapeId, (long unsigned int) label.size);
428     }
429
430     return 0;
431 }
432
433 int
434 bc_ScanDumps(struct bc_config *config, afs_int32 dbAddFlag, afs_int32 port)
435 {
436     struct rx_connection *tconn;
437     statusP statusPtr;
438     afs_uint32 taskId;
439     afs_int32 code = 0;
440
441     code = ConnectButc(config, port, &tconn);
442     if (code)
443         return (code);
444
445     code = TC_ScanDumps(tconn, dbAddFlag, &taskId);
446     if (code) {
447         afs_com_err(whoami, code, "; Failed to start scantape");
448         return (code);
449     }
450
451     /* create status monitor block */
452     statusPtr = createStatusNode();
453     lock_Status();
454     statusPtr->taskId = taskId;
455     statusPtr->port = port;
456     statusPtr->jobNumber = bc_jobNumber();
457     statusPtr->flags &= ~STARTING;      /* ok to examine */
458     sprintf(statusPtr->taskName, "Scantape");
459     unlock_Status();
460
461     return (0);
462 }
463
464 /*************/
465 /* utilities */
466 /*************/
467
468 /* get a connection to the tape controller */
469 afs_int32
470 bc_GetConn(struct bc_config *aconfig, afs_int32 aport,
471            struct rx_connection **tconn)
472 {
473     afs_uint32 host;
474     afs_int32 code;
475     unsigned short port;
476     static struct rx_securityClass *rxsc;
477     static afs_int32 scIndex;
478     struct bc_hostEntry *te;
479
480     *tconn = (struct rx_connection *)0;
481
482     /* use non-secure connections to butc */
483     if (!rxsc) {
484         struct afsconf_dir *dir;
485         afsconf_secflags flags = AFSCONF_SECOPTS_FALLBACK_NULL;
486         char *cname;
487
488         if (nobutcauth)
489             flags |= AFSCONF_SECOPTS_NOAUTH;
490         if (localauth) {
491             flags |= AFSCONF_SECOPTS_LOCALAUTH;
492             dir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
493         } else {
494             dir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
495         }
496         if (tcell[0] == '\0')
497             cname = NULL;
498         else
499             cname = tcell;
500         /* No need for cell info since butc is not a registered service */
501         code = afsconf_PickClientSecObj(dir, flags, NULL, cname, &rxsc, &scIndex,
502                                         NULL);
503         if (dir)
504             afsconf_Close(dir);
505         if (code)
506             return -1;
507     }
508     if (!rxsc || !aconfig)
509         return (-1);
510
511     for (te = aconfig->tapeHosts; te; te = te->next) {
512         if (te->portOffset == aport) {
513             /* found the right port */
514             host = te->addr.sin_addr.s_addr;
515             if (!host)
516                 return (BC_NOHOSTENTRY);        /* gethostbyname in bc_ParseHosts failed */
517
518             port = htons(BC_TAPEPORT + aport);
519
520             /* servers is 1 */
521             *tconn = rx_NewConnection(host, port, 1, rxsc, scIndex);
522             return ((*tconn ? 0 : -1));
523         }
524     }
525     return (BC_NOHOSTENTRY);
526 }
527
528 /* CheckTCVersion
529  *      make sure we are talking to a compatible butc process.
530  * exit:
531  *      0 - ok
532  *      -1 - not compatible
533  */
534
535 int
536 CheckTCVersion(struct rx_connection *tconn)
537 {
538     struct tc_tcInfo tci;
539     afs_int32 code;
540
541     code = TC_TCInfo(tconn, &tci);
542     if (code)
543         return (code);
544
545     if (tci.tcVersion != CUR_BUTC_VERSION)
546         return (BC_VERSIONFAIL);
547
548     return 0;
549 }
550
551 int
552 ConnectButc(struct bc_config *config, afs_int32 port,
553             struct rx_connection **tconn)
554 {
555     afs_int32 code;
556
557     code = bc_GetConn(config, port, tconn);
558     if (code) {
559         afs_com_err(whoami, code,
560                 "; Can't connect to tape coordinator at port %d", port);
561         return (code);
562     }
563
564     code = CheckTCVersion(*tconn);
565     if (code) {
566         rx_DestroyConnection(*tconn);
567
568         if (code == BC_VERSIONFAIL)
569             afs_com_err(whoami, code,
570                     "; Backup and butc are not the same version");
571         else
572             afs_com_err(whoami, code,
573                     "; Can't access tape coordinator at port %d", port);
574
575         return (code);
576     }
577
578     return (0);
579 }