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