878920d85cd2aa5e5c87ec36711e080631c9db8d
[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 RCSID
14     ("$Header$");
15
16 #include "vosutils.h"
17 #include "vsprocs.h"
18 #include "lockprocs.h"
19 #include <afs/afs_AdminErrors.h>
20 #include <string.h>
21
22 /*
23  * VLDB entry conversion routines.
24  * convert from one type of VLDB record to another.  There are only
25  * two types "old" and "new".
26  */
27
28 static int
29 OldVLDB_to_NewVLDB(struct vldbentry *source, struct nvldbentry *dest,
30                    afs_status_p st)
31 {
32     register int i;
33     int rc = 0;
34     afs_status_t tst = 0;
35
36     memset(dest, 0, sizeof(struct nvldbentry));
37     strncpy(dest->name, source->name, sizeof(dest->name));
38     for (i = 0; i < source->nServers; i++) {
39         dest->serverNumber[i] = source->serverNumber[i];
40         dest->serverPartition[i] = source->serverPartition[i];
41         dest->serverFlags[i] = source->serverFlags[i];
42     }
43     dest->nServers = source->nServers;
44     for (i = 0; i < MAXTYPES; i++)
45         dest->volumeId[i] = source->volumeId[i];
46     dest->cloneId = source->cloneId;
47     dest->flags = source->flags;
48
49     rc = 1;
50
51     if (st != NULL) {
52         *st = tst;
53     }
54     return rc;
55 }
56
57 /*
58  * We can fail to store the new to old VLDB record if there are more
59  * servers in the cell than the old format can handle.  If we fail,
60  * return an error.
61  */
62
63 static int
64 NewVLDB_to_OldVLDB(struct nvldbentry *source, struct vldbentry *dest,
65                    afs_status_p st)
66 {
67     register int i;
68     afs_status_t tst = 0;
69     int rc = 0;
70
71     memset(dest, 0, sizeof(struct vldbentry));
72     strncpy(dest->name, source->name, sizeof(dest->name));
73     if (source->nServers <= OMAXNSERVERS) {
74         for (i = 0; i < source->nServers; i++) {
75             dest->serverNumber[i] = source->serverNumber[i];
76             dest->serverPartition[i] = source->serverPartition[i];
77             dest->serverFlags[i] = source->serverFlags[i];
78         }
79         dest->nServers = i;
80         for (i = 0; i < MAXTYPES; i++)
81             dest->volumeId[i] = source->volumeId[i];
82         dest->cloneId = source->cloneId;
83         dest->flags = source->flags;
84         rc = 1;
85     } else {
86         tst = VL_BADSERVER;
87     }
88
89     if (st != NULL) {
90         *st = tst;
91     }
92     return rc;
93 }
94
95 int
96 VLDB_CreateEntry(afs_cell_handle_p cellHandle, struct nvldbentry *entryp,
97                  afs_status_p st)
98 {
99     struct vldbentry oentry;
100     afs_status_t tst = 0;
101     int rc = 0;
102
103     do {
104         if (cellHandle->vos_new) {
105             tst = ubik_VL_CreateEntryN(cellHandle->vos, 0, entryp);
106             if (tst) {
107                 if (tst == RXGEN_OPCODE) {
108                     cellHandle->vos_new = 0;
109                 }
110             } else {
111                 rc = 1;
112             }
113         } else {
114             if (NewVLDB_to_OldVLDB(entryp, &oentry, &tst)) {
115                 tst = ubik_VL_CreateEntry(cellHandle->vos, 0, &oentry);
116                 if (!tst) {
117                     rc = 1;
118                 }
119             }
120         }
121     } while (tst == RXGEN_OPCODE);
122
123     if (st != NULL) {
124         *st = tst;
125     }
126     return rc;
127 }
128
129 int
130 aVLDB_GetEntryByID(afs_cell_handle_p cellHandle, afs_int32 volid,
131                   afs_int32 voltype, struct nvldbentry *entryp,
132                   afs_status_p st)
133 {
134     struct vldbentry oentry;
135     afs_status_t tst = 0;
136     int rc = 0;
137
138     do {
139         if (cellHandle->vos_new) {
140             tst =
141                 ubik_VL_GetEntryByIDN(cellHandle->vos, 0, volid,
142                           voltype, entryp);
143             if (tst) {
144                 if (tst == RXGEN_OPCODE) {
145                     cellHandle->vos_new = 0;
146                 }
147             } else {
148                 rc = 1;
149             }
150         } else {
151             tst =
152                 ubik_VL_GetEntryByID(cellHandle->vos, 0, volid, voltype,
153                           &oentry);
154             if (tst == 0) {
155                 rc = OldVLDB_to_NewVLDB(&oentry, entryp, &tst);
156             }
157         }
158
159     } while (tst == RXGEN_OPCODE);
160
161     if (st != NULL) {
162         *st = tst;
163     }
164     return rc;
165 }
166
167 int
168 aVLDB_GetEntryByName(afs_cell_handle_p cellHandle, const char *namep,
169                     struct nvldbentry *entryp, afs_status_p st)
170 {
171     struct vldbentry oentry;
172     afs_status_t tst = 0;
173     int rc = 0;
174
175     do {
176         if (cellHandle->vos_new) {
177             tst =
178                 ubik_VL_GetEntryByNameN(cellHandle->vos, 0, namep,
179                           entryp);
180             if (tst) {
181                 if (tst == RXGEN_OPCODE) {
182                     cellHandle->vos_new = 0;
183                 }
184             } else {
185                 rc = 1;
186             }
187         } else {
188             tst =
189                 ubik_VL_GetEntryByNameO(cellHandle->vos, 0, namep,
190                           &oentry);
191             if (tst == 0) {
192                 rc = OldVLDB_to_NewVLDB(&oentry, entryp, &tst);
193             }
194         }
195
196     } while (tst == RXGEN_OPCODE);
197
198     if (st != NULL) {
199         *st = tst;
200     }
201     return rc;
202 }
203
204 int
205 VLDB_ReplaceEntry(afs_cell_handle_p cellHandle, afs_int32 volid,
206                   afs_int32 voltype, struct nvldbentry *entryp,
207                   afs_int32 releasetype, afs_status_p st)
208 {
209     struct vldbentry oentry;
210     afs_status_t tst = 0;
211     int rc = 0;
212
213     do {
214         if (cellHandle->vos_new) {
215             tst =
216                 ubik_VL_ReplaceEntryN(cellHandle->vos, 0, volid,
217                           voltype, entryp, releasetype);
218             if (tst) {
219                 if (tst == RXGEN_OPCODE) {
220                     cellHandle->vos_new = 0;
221                 }
222             } else {
223                 rc = 1;
224             }
225         } else {
226             if (NewVLDB_to_OldVLDB(entryp, &oentry, &tst)) {
227                 tst =
228                     ubik_VL_ReplaceEntry(cellHandle->vos, 0, volid,
229                               voltype, &oentry, releasetype);
230                 if (!tst) {
231                     rc = 1;
232                 }
233             }
234         }
235     } while (tst == RXGEN_OPCODE);
236
237     if (st != NULL) {
238         *st = tst;
239     }
240     return rc;
241 }
242
243 int
244 VLDB_ListAttributes(afs_cell_handle_p cellHandle,
245                     VldbListByAttributes * attrp, afs_int32 * entriesp,
246                     nbulkentries * blkentriesp, afs_status_p st)
247 {
248     bulkentries arrayEntries;
249     int i;
250     afs_status_t tst = 0;
251     int rc = 0;
252
253     do {
254         if (cellHandle->vos_new) {
255             tst =
256                 ubik_VL_ListAttributesN(cellHandle->vos, 0, attrp,
257                           entriesp, blkentriesp);
258             if (tst) {
259                 if (tst == RXGEN_OPCODE) {
260                     cellHandle->vos_new = 0;
261                 }
262             } else {
263                 rc = 1;
264             }
265         } else {
266             memset((void *)&arrayEntries, 0, sizeof(arrayEntries));
267             tst =
268                 ubik_VL_ListAttributes(cellHandle->vos, 0, attrp,
269                           entriesp, &arrayEntries);
270             if (tst == 0) {
271                 blkentriesp->nbulkentries_val =
272                     (nvldbentry *) malloc(*entriesp * sizeof(*blkentriesp));
273                 if (blkentriesp->nbulkentries_val != NULL) {
274                     for (i = 0; i < *entriesp; i++) {
275                         OldVLDB_to_NewVLDB((struct vldbentry *)&arrayEntries.
276                                            bulkentries_val[i],
277                                            (struct nvldbentry *)&blkentriesp->
278                                            nbulkentries_val[i], &tst);
279                     }
280                 } else {
281                     tst = ADMNOMEM;
282                 }
283                 if (arrayEntries.bulkentries_val) {
284                     free(arrayEntries.bulkentries_val);
285                 }
286                 rc = 1;
287             }
288         }
289
290     } while (tst == RXGEN_OPCODE);
291
292     if (st != NULL) {
293         *st = tst;
294     }
295     return rc;
296 }
297
298 int
299 VLDB_ListAttributesN2(afs_cell_handle_p cellHandle,
300                       VldbListByAttributes * attrp, char *name,
301                       afs_int32 thisindex, afs_int32 * nentriesp,
302                       nbulkentries * blkentriesp, afs_int32 * nextindexp,
303                       afs_status_p st)
304 {
305     int rc = 0;
306     afs_status_t tst = 0;
307
308     tst =
309         ubik_VL_ListAttributesN2(cellHandle->vos, 0, attrp,
310                   (name ? name : ""), thisindex, nentriesp, blkentriesp,
311                   nextindexp);
312     if (!tst) {
313         rc = 1;
314     }
315
316     if (st != NULL) {
317         *st = tst;
318     }
319     return rc;
320 }
321
322 int
323 VLDB_IsSameAddrs(afs_cell_handle_p cellHandle, afs_int32 serv1,
324                  afs_int32 serv2, int *equal, afs_status_p st)
325 {
326     int rc = 0;
327     afs_status_t tst = 0;
328
329     ListAddrByAttributes attrs;
330     bulkaddrs addrs;
331     afs_uint32 *addrp, 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, unsigned int 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 }