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