c2325bc810a3181c0569bd2da163d977d3a8c81e
[openafs.git] / src / libadmin / vos / vosutils.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 <roken.h>
14
15 #include "vosutils.h"
16 #include "vsprocs.h"
17 #include "lockprocs.h"
18 #include <afs/afs_AdminErrors.h>
19 #include <string.h>
20
21 /*
22  * VLDB entry conversion routines.
23  * convert from one type of VLDB record to another.  There are only
24  * two types "old" and "new".
25  */
26
27 static int
28 OldVLDB_to_NewVLDB(struct vldbentry *source, struct nvldbentry *dest,
29                    afs_status_p st)
30 {
31     int i;
32     int rc = 0;
33     afs_status_t tst = 0;
34
35     memset(dest, 0, sizeof(struct nvldbentry));
36     strncpy(dest->name, source->name, sizeof(dest->name));
37     for (i = 0; i < source->nServers; i++) {
38         dest->serverNumber[i] = source->serverNumber[i];
39         dest->serverPartition[i] = source->serverPartition[i];
40         dest->serverFlags[i] = source->serverFlags[i];
41     }
42     dest->nServers = source->nServers;
43     for (i = 0; i < MAXTYPES; i++)
44         dest->volumeId[i] = source->volumeId[i];
45     dest->cloneId = source->cloneId;
46     dest->flags = source->flags;
47
48     rc = 1;
49
50     if (st != NULL) {
51         *st = tst;
52     }
53     return rc;
54 }
55
56 /*
57  * We can fail to store the new to old VLDB record if there are more
58  * servers in the cell than the old format can handle.  If we fail,
59  * return an error.
60  */
61
62 static int
63 NewVLDB_to_OldVLDB(struct nvldbentry *source, struct vldbentry *dest,
64                    afs_status_p st)
65 {
66     int i;
67     afs_status_t tst = 0;
68     int rc = 0;
69
70     memset(dest, 0, sizeof(struct vldbentry));
71     strncpy(dest->name, source->name, sizeof(dest->name));
72     if (source->nServers <= OMAXNSERVERS) {
73         for (i = 0; i < source->nServers; i++) {
74             dest->serverNumber[i] = source->serverNumber[i];
75             dest->serverPartition[i] = source->serverPartition[i];
76             dest->serverFlags[i] = source->serverFlags[i];
77         }
78         dest->nServers = i;
79         for (i = 0; i < MAXTYPES; i++)
80             dest->volumeId[i] = source->volumeId[i];
81         dest->cloneId = source->cloneId;
82         dest->flags = source->flags;
83         rc = 1;
84     } else {
85         tst = VL_BADSERVER;
86     }
87
88     if (st != NULL) {
89         *st = tst;
90     }
91     return rc;
92 }
93
94 int
95 VLDB_CreateEntry(afs_cell_handle_p cellHandle, struct nvldbentry *entryp,
96                  afs_status_p st)
97 {
98     struct vldbentry oentry;
99     afs_status_t tst = 0;
100     int rc = 0;
101
102     do {
103         if (cellHandle->vos_new) {
104             tst = ubik_VL_CreateEntryN(cellHandle->vos, 0, entryp);
105             if (tst) {
106                 if (tst == RXGEN_OPCODE) {
107                     cellHandle->vos_new = 0;
108                 }
109             } else {
110                 rc = 1;
111             }
112         } else {
113             if (NewVLDB_to_OldVLDB(entryp, &oentry, &tst)) {
114                 tst = ubik_VL_CreateEntry(cellHandle->vos, 0, &oentry);
115                 if (!tst) {
116                     rc = 1;
117                 }
118             }
119         }
120     } while (tst == RXGEN_OPCODE);
121
122     if (st != NULL) {
123         *st = tst;
124     }
125     return rc;
126 }
127
128 int
129 aVLDB_GetEntryByID(afs_cell_handle_p cellHandle, afs_uint32 volid,
130                   afs_int32 voltype, struct nvldbentry *entryp,
131                   afs_status_p st)
132 {
133     struct vldbentry oentry;
134     afs_status_t tst = 0;
135     int rc = 0;
136
137     do {
138         if (cellHandle->vos_new) {
139             tst =
140                 ubik_VL_GetEntryByIDN(cellHandle->vos, 0, volid,
141                           voltype, entryp);
142             if (tst) {
143                 if (tst == RXGEN_OPCODE) {
144                     cellHandle->vos_new = 0;
145                 }
146             } else {
147                 rc = 1;
148             }
149         } else {
150             tst =
151                 ubik_VL_GetEntryByID(cellHandle->vos, 0, volid, voltype,
152                           &oentry);
153             if (tst == 0) {
154                 rc = OldVLDB_to_NewVLDB(&oentry, entryp, &tst);
155             }
156         }
157
158     } while (tst == RXGEN_OPCODE);
159
160     if (st != NULL) {
161         *st = tst;
162     }
163     return rc;
164 }
165
166 int
167 aVLDB_GetEntryByName(afs_cell_handle_p cellHandle, char *namep,
168                     struct nvldbentry *entryp, afs_status_p st)
169 {
170     struct vldbentry oentry;
171     afs_status_t tst = 0;
172     int rc = 0;
173
174     do {
175         if (cellHandle->vos_new) {
176             tst =
177                 ubik_VL_GetEntryByNameN(cellHandle->vos, 0, namep,
178                           entryp);
179             if (tst) {
180                 if (tst == RXGEN_OPCODE) {
181                     cellHandle->vos_new = 0;
182                 }
183             } else {
184                 rc = 1;
185             }
186         } else {
187             tst =
188                 ubik_VL_GetEntryByNameO(cellHandle->vos, 0, namep,
189                           &oentry);
190             if (tst == 0) {
191                 rc = OldVLDB_to_NewVLDB(&oentry, entryp, &tst);
192             }
193         }
194
195     } while (tst == RXGEN_OPCODE);
196
197     if (st != NULL) {
198         *st = tst;
199     }
200     return rc;
201 }
202
203 int
204 VLDB_ReplaceEntry(afs_cell_handle_p cellHandle, afs_uint32 volid,
205                   afs_int32 voltype, struct nvldbentry *entryp,
206                   afs_int32 releasetype, afs_status_p st)
207 {
208     struct vldbentry oentry;
209     afs_status_t tst = 0;
210     int rc = 0;
211
212     do {
213         if (cellHandle->vos_new) {
214             tst =
215                 ubik_VL_ReplaceEntryN(cellHandle->vos, 0, volid,
216                           voltype, entryp, releasetype);
217             if (tst) {
218                 if (tst == RXGEN_OPCODE) {
219                     cellHandle->vos_new = 0;
220                 }
221             } else {
222                 rc = 1;
223             }
224         } else {
225             if (NewVLDB_to_OldVLDB(entryp, &oentry, &tst)) {
226                 tst =
227                     ubik_VL_ReplaceEntry(cellHandle->vos, 0, volid,
228                               voltype, &oentry, releasetype);
229                 if (!tst) {
230                     rc = 1;
231                 }
232             }
233         }
234     } while (tst == RXGEN_OPCODE);
235
236     if (st != NULL) {
237         *st = tst;
238     }
239     return rc;
240 }
241
242 int
243 VLDB_ListAttributes(afs_cell_handle_p cellHandle,
244                     VldbListByAttributes * attrp, afs_int32 * entriesp,
245                     nbulkentries * blkentriesp, afs_status_p st)
246 {
247     bulkentries arrayEntries;
248     int i;
249     afs_status_t tst = 0;
250     int rc = 0;
251
252     do {
253         if (cellHandle->vos_new) {
254             tst =
255                 ubik_VL_ListAttributesN(cellHandle->vos, 0, attrp,
256                           entriesp, blkentriesp);
257             if (tst) {
258                 if (tst == RXGEN_OPCODE) {
259                     cellHandle->vos_new = 0;
260                 }
261             } else {
262                 rc = 1;
263             }
264         } else {
265             memset((void *)&arrayEntries, 0, sizeof(arrayEntries));
266             tst =
267                 ubik_VL_ListAttributes(cellHandle->vos, 0, attrp,
268                           entriesp, &arrayEntries);
269             if (tst == 0) {
270                 blkentriesp->nbulkentries_val =
271                     (nvldbentry *) malloc(*entriesp * sizeof(*blkentriesp));
272                 if (blkentriesp->nbulkentries_val != NULL) {
273                     for (i = 0; i < *entriesp; i++) {
274                         OldVLDB_to_NewVLDB((struct vldbentry *)&arrayEntries.
275                                            bulkentries_val[i],
276                                            (struct nvldbentry *)&blkentriesp->
277                                            nbulkentries_val[i], &tst);
278                     }
279                 } else {
280                     tst = ADMNOMEM;
281                 }
282                 if (arrayEntries.bulkentries_val) {
283                     free(arrayEntries.bulkentries_val);
284                 }
285                 rc = 1;
286             }
287         }
288
289     } while (tst == RXGEN_OPCODE);
290
291     if (st != NULL) {
292         *st = tst;
293     }
294     return rc;
295 }
296
297 int
298 VLDB_ListAttributesN2(afs_cell_handle_p cellHandle,
299                       VldbListByAttributes * attrp, char *name,
300                       afs_int32 thisindex, afs_int32 * nentriesp,
301                       nbulkentries * blkentriesp, afs_int32 * nextindexp,
302                       afs_status_p st)
303 {
304     int rc = 0;
305     afs_status_t tst = 0;
306
307     tst =
308         ubik_VL_ListAttributesN2(cellHandle->vos, 0, attrp,
309                   (name ? name : ""), thisindex, nentriesp, blkentriesp,
310                   nextindexp);
311     if (!tst) {
312         rc = 1;
313     }
314
315     if (st != NULL) {
316         *st = tst;
317     }
318     return rc;
319 }
320
321 int
322 VLDB_IsSameAddrs(afs_cell_handle_p cellHandle, afs_int32 serv1,
323                  afs_int32 serv2, int *equal, afs_status_p st)
324 {
325     int rc = 0;
326     afs_status_t tst = 0;
327
328     ListAddrByAttributes attrs;
329     bulkaddrs addrs;
330     afs_uint32 *addrp;
331     afs_int32 nentries, unique, i;
332     afsUUID uuid;
333
334     *equal = 0;
335
336     if (serv1 == serv2) {
337         *equal = 1;
338         rc = 1;
339         goto fail_VLDB_IsSameAddrs;
340     }
341
342     memset(&attrs, 0, sizeof(attrs));
343     attrs.Mask = VLADDR_IPADDR;
344     attrs.ipaddr = serv1;
345     memset(&addrs, 0, sizeof(addrs));
346     memset(&uuid, 0, sizeof(uuid));
347     tst =
348         ubik_VL_GetAddrsU(cellHandle->vos, 0, &attrs, &uuid, &unique,
349                   &nentries, &addrs);
350     if (tst) {
351         *equal = 0;
352         goto fail_VLDB_IsSameAddrs;
353     }
354
355     addrp = addrs.bulkaddrs_val;
356     for (i = 0; i < nentries; i++, addrp++) {
357         if (serv2 == *addrp) {
358             *equal = 1;
359             break;
360         }
361     }
362     rc = 1;
363
364   fail_VLDB_IsSameAddrs:
365
366     if (st != NULL) {
367         *st = tst;
368     }
369     return rc;
370 }
371
372 /*
373  * GetVolumeInfo - retrieve information about a particular volume.
374  *
375  * PARAMETERS
376  *
377  * IN cellHandle - a handle that corresponds to the cell where the volume
378  * is located.
379  *
380  * IN volid - the volume to be retrieved.
381  *
382  * OUT rentry - the vldb entry of the volume.
383  *
384  * OUT server - the address of the server where the volume resides in 
385  * host byte order.
386  *
387  * OUT partition - the volume to be retrieved.
388  *
389  * OUT voltype - the type of volume retrieved.
390  *
391  * LOCKS
392  *
393  * No locks are obtained or released by this function
394  *
395  * RETURN CODES
396  *
397  * Returns != 0 upon successful completion.
398  */
399
400 int
401 GetVolumeInfo(afs_cell_handle_p cellHandle, afs_uint32 volid,
402               struct nvldbentry *rentry, afs_int32 * server,
403               afs_int32 * partition, afs_int32 * voltype, afs_status_p st)
404 {
405     int rc = 0;
406     afs_status_t tst;
407     int i, index = -1;
408
409     if (!aVLDB_GetEntryByID(cellHandle, volid, -1, rentry, &tst)) {
410         rc = 0;
411         goto fail_GetVolumeInfo;
412     }
413
414     if (volid == rentry->volumeId[ROVOL]) {
415         *voltype = ROVOL;
416         for (i = 0; i < rentry->nServers; i++) {
417             if ((index == -1) && (rentry->serverFlags[i] & ITSROVOL)
418                 && !(rentry->serverFlags[i] & RO_DONTUSE))
419                 index = i;
420         }
421         if (index == -1) {
422             tst = 1;
423             goto fail_GetVolumeInfo;
424         }
425         *server = rentry->serverNumber[index];
426         *partition = rentry->serverPartition[index];
427         rc = 1;
428         goto fail_GetVolumeInfo;
429     }
430
431     if ((index = Lp_GetRwIndex(cellHandle, rentry, &tst)) < 0) {
432         goto fail_GetVolumeInfo;
433     }
434     if (volid == rentry->volumeId[RWVOL]) {
435         *voltype = RWVOL;
436         *server = rentry->serverNumber[index];
437         *partition = rentry->serverPartition[index];
438     } else if (volid == rentry->volumeId[BACKVOL]) {
439         *voltype = BACKVOL;
440         *server = rentry->serverNumber[index];
441         *partition = rentry->serverPartition[index];
442     }
443     rc = 1;
444
445   fail_GetVolumeInfo:
446
447     if (st != NULL) {
448         *st = tst;
449     }
450     return rc;
451 }
452
453 /*
454  * ValidateVolumeName - validate a potential volume name
455  *
456  * PARAMETERS
457  *
458  * IN volumeName - the volume name to be validated.
459  *
460  * LOCKS
461  *
462  * No locks are obtained or released by this function
463  *
464  * RETURN CODES
465  *
466  * Returns != 0 upon successful completion.
467  */
468
469 int
470 ValidateVolumeName(const char *volumeName, afs_status_p st)
471 {
472     int rc = 0;
473     afs_status_t tst = 0;
474     size_t len;
475
476     if ((volumeName == NULL) || (*volumeName == 0)) {
477         tst = ADMVOSVOLUMENAMENULL;
478         goto fail_ValidateVolumeName;
479     }
480
481     if (!ISNAMEVALID(volumeName)) {
482         tst = ADMVOSVOLUMENAMETOOLONG;
483         goto fail_ValidateVolumeName;
484     }
485
486     len = strlen(volumeName);
487
488     if (((len > 8) && (!strcmp(&volumeName[len - 9], ".readonly")))
489         || ((len > 6) && (!strcmp(&volumeName[len - 7], ".backup")))) {
490         tst = ADMVOSVOLUMENAMEINVALID;
491         goto fail_ValidateVolumeName;
492     }
493
494     rc = 1;
495
496   fail_ValidateVolumeName:
497
498     if (st != NULL) {
499         *st = tst;
500     }
501
502     return rc;
503 }
504
505 /*extract the name of volume <name> without readonly or backup suffixes
506  * and return the result as <rname>.
507  */
508 int
509 vsu_ExtractName(char *rname, char *name)
510 {
511     char sname[32];
512     size_t total;
513
514     strncpy(sname, name, 32);
515     sname[31] ='\0';
516     total = strlen(sname);
517     if ((total > 9) && (!strcmp(&sname[total - 9], ".readonly"))) {
518         /*discard the last 8 chars */
519         sname[total - 9] = '\0';
520         strcpy(rname, sname);
521         return 0;
522     } else if ((total > 7) && (!strcmp(&sname[total - 7], ".backup"))) {
523         /*discard last 6 chars */
524         sname[total - 7] = '\0';
525         strcpy(rname, sname);
526         return 0;
527     } else {
528         strncpy(rname, name, VOLSER_OLDMAXVOLNAME);
529         return -1;
530     }
531 }
532
533
534
535 /*
536  * AddressMatch - determines if an IP address matches a pattern
537  *
538  * PARAMETERS
539  *
540  * IN addrTest - the IP address to test, in either byte-order
541  * IN addrPattern - the IP address pattern, in the same byte-order
542  *
543  * LOCKS
544  *
545  * No locks are obtained or released by this function
546  *
547  * RETURN CODES
548  *
549  * Returns != 0 if the address matches the pattern specified
550  * (where 255 in any byte in the pattern indicates a wildcard).
551  */
552
553 int
554 AddressMatch(int addrTest, int addrPattern)
555 {
556     int bTest;
557     int bPattern;
558
559     /* Test the high byte */
560     bTest = addrTest >> 24;
561     bPattern = addrPattern >> 24;
562     if ((bTest != bPattern) && (bPattern != 255)) {
563         return FALSE;
564     }
565
566     /* Test the next-highest byte */
567     bTest = (addrTest >> 16) & 255;
568     bPattern = (addrPattern >> 16) & 255;
569     if ((bTest != bPattern) && (bPattern != 255)) {
570         return FALSE;
571     }
572
573     /* Test the next-to-lowest byte */
574     bTest = (addrTest >> 8) & 255;
575     bPattern = (addrPattern >> 8) & 255;
576     if ((bTest != bPattern) && (bPattern != 255)) {
577         return FALSE;
578     }
579
580     /* Test the low byte */
581     bTest = addrTest & 255;
582     bPattern = addrPattern & 255;
583     if ((bTest != bPattern) && (bPattern != 255)) {
584         return FALSE;
585     }
586
587     return TRUE;
588 }
589
590
591 /*
592  * RemoveBadAddresses - (optionally) removes addresses that are better ignored
593  *
594  * PARAMETERS
595  *
596  * IN OUT totalp - the number of addresses in the addrsp structure
597  * IN OUT addrsp - a bulk array of addresses
598  *
599  * LOCKS
600  *
601  * No locks are obtained or released by this function
602  *
603  * RETURN CODES
604  *
605  * Returns != 0 upon successful completion.
606  */
607
608 static pthread_once_t badaddr_init_once = PTHREAD_ONCE_INIT;
609 static int addr_to_skip;
610
611 static void
612 badaddr_once(void)
613 {
614
615 #ifdef AFS_NT40_ENV
616
617 #define cszREG_IGNORE_KEY "Software\\OpenAFS\\AFS Control Center"
618 #define cszREG_IGNORE_VALUE "IgnoreBadAddrs"
619
620     /*
621      * In order for this routine to do anything, it must first validate
622      * that the user of this machine wants this filtering to take place.
623      * There is an undocumented registry value which signifies that it's
624      * okay to filter bogus IP addresses--and, moreover, indicates
625      * the range of values which may be ignored. Check that value.
626      */
627
628     HKEY hk;
629     addr_to_skip = 0;           /* don't ignore any addrs unless we find otherwise */
630     if (RegOpenKey(HKEY_LOCAL_MACHINE, cszREG_IGNORE_KEY, &hk) == 0) {
631         DWORD dwType = REG_DWORD;
632         DWORD dwSize = sizeof(addr_to_skip);
633         RegQueryValueEx(hk, cszREG_IGNORE_VALUE, 0, &dwType,
634                         (PBYTE) & addr_to_skip, &dwSize);
635         RegCloseKey(hk);
636     }
637 #else
638
639     /*
640      * We only support this functionality (so far) on NT; on other
641      * platforms, we'll never ignore IP addresses. If the feature
642      * is needed in the future, here's the place to add it.
643      *
644      */
645
646     addr_to_skip = 0;           /* don't skip any addresses */
647
648 #endif
649
650 }
651
652 int
653 RemoveBadAddresses(afs_int32 * totalp, bulkaddrs * addrsp)
654 {
655     pthread_once(&badaddr_init_once, badaddr_once);
656
657     /*
658      * If we've been requested to skip anything, addr_to_skip will be
659      * non-zero. It's actually an IP address of the form:
660      *    10.0.0.255
661      * A "255" means any value is acceptable, and any other value means
662      * the to-be-skipped address must match that value.
663      */
664
665     if (addr_to_skip && addrsp && addrsp->bulkaddrs_val) {
666         size_t iiWrite = 0;
667         size_t iiRead = 0;
668         for (; iiRead < addrsp->bulkaddrs_len; ++iiRead) {
669
670             /*
671              * Check this IP address to see if it should be skipped.
672              */
673
674             if (!AddressMatch(addrsp->bulkaddrs_val[iiRead], addr_to_skip)) {
675
676                 /*
677                  * The address is okay; make sure it stays in the list.
678                  */
679
680                 if (iiWrite != iiRead) {
681                     addrsp->bulkaddrs_val[iiWrite] =
682                         addrsp->bulkaddrs_val[iiRead];
683                 }
684
685                 ++iiWrite;
686             }
687         }
688         *totalp = (afs_int32) iiWrite;
689         addrsp->bulkaddrs_len = iiWrite;
690     }
691
692     return TRUE;
693 }