3fcab998909e3578cd988a0e13aff8ef9bfc0f55
[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 <afs/afs_AdminErrors.h>
16
17 #include "vosutils.h"
18 #include "vsprocs.h"
19 #include "lockprocs.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                 if (*entriesp < 0)
263                     *entriesp = 0;
264                 if (*entriesp > blkentriesp->nbulkentries_len)
265                     *entriesp = blkentriesp->nbulkentries_len;
266                 rc = 1;
267             }
268         } else {
269             memset((void *)&arrayEntries, 0, sizeof(arrayEntries));
270             tst =
271                 ubik_VL_ListAttributes(cellHandle->vos, 0, attrp,
272                           entriesp, &arrayEntries);
273             if (tst == 0) {
274
275                 if (*entriesp < 0)
276                     *entriesp = 0;
277                 if (*entriesp > arrayEntries.bulkentries_len)
278                     *entriesp = arrayEntries.bulkentries_len;
279
280                 blkentriesp->nbulkentries_val =
281                     malloc(*entriesp * sizeof(*blkentriesp));
282                 if (blkentriesp->nbulkentries_val != NULL) {
283                     for (i = 0; i < *entriesp; i++) {
284                         OldVLDB_to_NewVLDB((struct vldbentry *)&arrayEntries.
285                                            bulkentries_val[i],
286                                            (struct nvldbentry *)&blkentriesp->
287                                            nbulkentries_val[i], &tst);
288                     }
289                 } else {
290                     tst = ADMNOMEM;
291                 }
292                 if (arrayEntries.bulkentries_val) {
293                     free(arrayEntries.bulkentries_val);
294                 }
295
296                 rc = 1;
297             }
298         }
299
300     } while (tst == RXGEN_OPCODE);
301
302     if (st != NULL) {
303         *st = tst;
304     }
305     return rc;
306 }
307
308 int
309 VLDB_ListAttributesN2(afs_cell_handle_p cellHandle,
310                       VldbListByAttributes * attrp, char *name,
311                       afs_int32 thisindex, afs_int32 * nentriesp,
312                       nbulkentries * blkentriesp, afs_int32 * nextindexp,
313                       afs_status_p st)
314 {
315     int rc = 0;
316     afs_status_t tst = 0;
317
318     tst =
319         ubik_VL_ListAttributesN2(cellHandle->vos, 0, attrp,
320                   (name ? name : ""), thisindex, nentriesp, blkentriesp,
321                   nextindexp);
322     if (!tst) {
323         rc = 1;
324     }
325
326     if (st != NULL) {
327         *st = tst;
328     }
329     return rc;
330 }
331
332 int
333 VLDB_IsSameAddrs(afs_cell_handle_p cellHandle, afs_int32 serv1,
334                  afs_int32 serv2, int *equal, afs_status_p st)
335 {
336     int rc = 0;
337     afs_status_t tst = 0;
338
339     ListAddrByAttributes attrs;
340     bulkaddrs addrs;
341     afs_uint32 *addrp;
342     afs_int32 nentries, unique, i;
343     afsUUID uuid;
344
345     *equal = 0;
346
347     if (serv1 == serv2) {
348         *equal = 1;
349         rc = 1;
350         goto fail_VLDB_IsSameAddrs;
351     }
352
353     memset(&attrs, 0, sizeof(attrs));
354     attrs.Mask = VLADDR_IPADDR;
355     attrs.ipaddr = serv1;
356     memset(&addrs, 0, sizeof(addrs));
357     memset(&uuid, 0, sizeof(uuid));
358     tst =
359         ubik_VL_GetAddrsU(cellHandle->vos, 0, &attrs, &uuid, &unique,
360                   &nentries, &addrs);
361     if (tst) {
362         *equal = 0;
363         goto fail_VLDB_IsSameAddrs;
364     }
365
366     addrp = addrs.bulkaddrs_val;
367     for (i = 0; i < nentries; i++, addrp++) {
368         if (serv2 == *addrp) {
369             *equal = 1;
370             break;
371         }
372     }
373     rc = 1;
374
375   fail_VLDB_IsSameAddrs:
376
377     if (st != NULL) {
378         *st = tst;
379     }
380     return rc;
381 }
382
383 /*
384  * GetVolumeInfo - retrieve information about a particular volume.
385  *
386  * PARAMETERS
387  *
388  * IN cellHandle - a handle that corresponds to the cell where the volume
389  * is located.
390  *
391  * IN volid - the volume to be retrieved.
392  *
393  * OUT rentry - the vldb entry of the volume.
394  *
395  * OUT server - the address of the server where the volume resides in 
396  * host byte order.
397  *
398  * OUT partition - the volume to be retrieved.
399  *
400  * OUT voltype - the type of volume retrieved.
401  *
402  * LOCKS
403  *
404  * No locks are obtained or released by this function
405  *
406  * RETURN CODES
407  *
408  * Returns != 0 upon successful completion.
409  */
410
411 int
412 GetVolumeInfo(afs_cell_handle_p cellHandle, afs_uint32 volid,
413               struct nvldbentry *rentry, afs_int32 * server,
414               afs_int32 * partition, afs_int32 * voltype, afs_status_p st)
415 {
416     int rc = 0;
417     afs_status_t tst;
418     int i, index = -1;
419
420     if (!aVLDB_GetEntryByID(cellHandle, volid, -1, rentry, &tst)) {
421         rc = 0;
422         goto fail_GetVolumeInfo;
423     }
424
425     if (volid == rentry->volumeId[ROVOL]) {
426         *voltype = ROVOL;
427         for (i = 0; i < rentry->nServers; i++) {
428             if ((index == -1) && (rentry->serverFlags[i] & ITSROVOL)
429                 && !(rentry->serverFlags[i] & RO_DONTUSE))
430                 index = i;
431         }
432         if (index == -1) {
433             tst = 1;
434             goto fail_GetVolumeInfo;
435         }
436         *server = rentry->serverNumber[index];
437         *partition = rentry->serverPartition[index];
438         rc = 1;
439         goto fail_GetVolumeInfo;
440     }
441
442     if ((index = Lp_GetRwIndex(cellHandle, rentry, &tst)) < 0) {
443         goto fail_GetVolumeInfo;
444     }
445     if (volid == rentry->volumeId[RWVOL]) {
446         *voltype = RWVOL;
447         *server = rentry->serverNumber[index];
448         *partition = rentry->serverPartition[index];
449     } else if (volid == rentry->volumeId[BACKVOL]) {
450         *voltype = BACKVOL;
451         *server = rentry->serverNumber[index];
452         *partition = rentry->serverPartition[index];
453     }
454     rc = 1;
455
456   fail_GetVolumeInfo:
457
458     if (st != NULL) {
459         *st = tst;
460     }
461     return rc;
462 }
463
464 /*
465  * ValidateVolumeName - validate a potential volume name
466  *
467  * PARAMETERS
468  *
469  * IN volumeName - the volume name to be validated.
470  *
471  * LOCKS
472  *
473  * No locks are obtained or released by this function
474  *
475  * RETURN CODES
476  *
477  * Returns != 0 upon successful completion.
478  */
479
480 int
481 ValidateVolumeName(const char *volumeName, afs_status_p st)
482 {
483     int rc = 0;
484     afs_status_t tst = 0;
485     size_t len;
486
487     if ((volumeName == NULL) || (*volumeName == 0)) {
488         tst = ADMVOSVOLUMENAMENULL;
489         goto fail_ValidateVolumeName;
490     }
491
492     if (!ISNAMEVALID(volumeName)) {
493         tst = ADMVOSVOLUMENAMETOOLONG;
494         goto fail_ValidateVolumeName;
495     }
496
497     len = strlen(volumeName);
498
499     if (((len > 8) && (!strcmp(&volumeName[len - 9], ".readonly")))
500         || ((len > 6) && (!strcmp(&volumeName[len - 7], ".backup")))) {
501         tst = ADMVOSVOLUMENAMEINVALID;
502         goto fail_ValidateVolumeName;
503     }
504
505     rc = 1;
506
507   fail_ValidateVolumeName:
508
509     if (st != NULL) {
510         *st = tst;
511     }
512
513     return rc;
514 }
515
516 /*extract the name of volume <name> without readonly or backup suffixes
517  * and return the result as <rname>.
518  */
519 int
520 vsu_ExtractName(char *rname, char *name)
521 {
522     char sname[32];
523     size_t total;
524
525     strncpy(sname, name, 32);
526     sname[31] ='\0';
527     total = strlen(sname);
528     if ((total > 9) && (!strcmp(&sname[total - 9], ".readonly"))) {
529         /*discard the last 8 chars */
530         sname[total - 9] = '\0';
531         strcpy(rname, sname);
532         return 0;
533     } else if ((total > 7) && (!strcmp(&sname[total - 7], ".backup"))) {
534         /*discard last 6 chars */
535         sname[total - 7] = '\0';
536         strcpy(rname, sname);
537         return 0;
538     } else {
539         strncpy(rname, name, VOLSER_OLDMAXVOLNAME);
540         return -1;
541     }
542 }
543
544
545
546 /*
547  * AddressMatch - determines if an IP address matches a pattern
548  *
549  * PARAMETERS
550  *
551  * IN addrTest - the IP address to test, in either byte-order
552  * IN addrPattern - the IP address pattern, in the same byte-order
553  *
554  * LOCKS
555  *
556  * No locks are obtained or released by this function
557  *
558  * RETURN CODES
559  *
560  * Returns != 0 if the address matches the pattern specified
561  * (where 255 in any byte in the pattern indicates a wildcard).
562  */
563
564 int
565 AddressMatch(int addrTest, int addrPattern)
566 {
567     int bTest;
568     int bPattern;
569
570     /* Test the high byte */
571     bTest = (addrTest >> 24) & 255;
572     bPattern = (addrPattern >> 24) & 255;
573     if ((bTest != bPattern) && (bPattern != 255)) {
574         return FALSE;
575     }
576
577     /* Test the next-highest byte */
578     bTest = (addrTest >> 16) & 255;
579     bPattern = (addrPattern >> 16) & 255;
580     if ((bTest != bPattern) && (bPattern != 255)) {
581         return FALSE;
582     }
583
584     /* Test the next-to-lowest byte */
585     bTest = (addrTest >> 8) & 255;
586     bPattern = (addrPattern >> 8) & 255;
587     if ((bTest != bPattern) && (bPattern != 255)) {
588         return FALSE;
589     }
590
591     /* Test the low byte */
592     bTest = addrTest & 255;
593     bPattern = addrPattern & 255;
594     if ((bTest != bPattern) && (bPattern != 255)) {
595         return FALSE;
596     }
597
598     return TRUE;
599 }
600
601
602 /*
603  * RemoveBadAddresses - (optionally) removes addresses that are better ignored
604  *
605  * PARAMETERS
606  *
607  * IN OUT totalp - the number of addresses in the addrsp structure
608  * IN OUT addrsp - a bulk array of addresses
609  *
610  * LOCKS
611  *
612  * No locks are obtained or released by this function
613  *
614  * RETURN CODES
615  *
616  * Returns != 0 upon successful completion.
617  */
618
619 static pthread_once_t badaddr_init_once = PTHREAD_ONCE_INIT;
620 static int addr_to_skip;
621
622 static void
623 badaddr_once(void)
624 {
625
626 #ifdef AFS_NT40_ENV
627
628 #define cszREG_IGNORE_KEY "Software\\OpenAFS\\AFS Control Center"
629 #define cszREG_IGNORE_VALUE "IgnoreBadAddrs"
630
631     /*
632      * In order for this routine to do anything, it must first validate
633      * that the user of this machine wants this filtering to take place.
634      * There is an undocumented registry value which signifies that it's
635      * okay to filter bogus IP addresses--and, moreover, indicates
636      * the range of values which may be ignored. Check that value.
637      */
638
639     HKEY hk;
640     addr_to_skip = 0;           /* don't ignore any addrs unless we find otherwise */
641     if (RegOpenKey(HKEY_LOCAL_MACHINE, cszREG_IGNORE_KEY, &hk) == 0) {
642         DWORD dwType = REG_DWORD;
643         DWORD dwSize = sizeof(addr_to_skip);
644         RegQueryValueEx(hk, cszREG_IGNORE_VALUE, 0, &dwType,
645                         (PBYTE) & addr_to_skip, &dwSize);
646         RegCloseKey(hk);
647     }
648 #else
649
650     /*
651      * We only support this functionality (so far) on NT; on other
652      * platforms, we'll never ignore IP addresses. If the feature
653      * is needed in the future, here's the place to add it.
654      *
655      */
656
657     addr_to_skip = 0;           /* don't skip any addresses */
658
659 #endif
660
661 }
662
663 int
664 RemoveBadAddresses(afs_int32 * totalp, bulkaddrs * addrsp)
665 {
666     pthread_once(&badaddr_init_once, badaddr_once);
667
668     /*
669      * If we've been requested to skip anything, addr_to_skip will be
670      * non-zero. It's actually an IP address of the form:
671      *    10.0.0.255
672      * A "255" means any value is acceptable, and any other value means
673      * the to-be-skipped address must match that value.
674      */
675
676     if (addr_to_skip && addrsp && addrsp->bulkaddrs_val) {
677         size_t iiWrite = 0;
678         size_t iiRead = 0;
679         for (; iiRead < addrsp->bulkaddrs_len; ++iiRead) {
680
681             /*
682              * Check this IP address to see if it should be skipped.
683              */
684
685             if (!AddressMatch(addrsp->bulkaddrs_val[iiRead], addr_to_skip)) {
686
687                 /*
688                  * The address is okay; make sure it stays in the list.
689                  */
690
691                 if (iiWrite != iiRead) {
692                     addrsp->bulkaddrs_val[iiWrite] =
693                         addrsp->bulkaddrs_val[iiRead];
694                 }
695
696                 ++iiWrite;
697             }
698         }
699         *totalp = (afs_int32) iiWrite;
700         addrsp->bulkaddrs_len = iiWrite;
701     }
702
703     return TRUE;
704 }