6ac500abd94b61394eb64fb7e175cff9394f4b6c
[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 "vosutils.h"
11 #include "vsprocs.h"
12 #include "lockprocs.h"
13 #include <afs/afs_AdminErrors.h>
14
15 /*
16  * Functions that aren't prototyped, but that we use
17  */
18
19 extern int VL_CreateEntryN(), VL_CreateEntry(), VL_GetEntryByIDN(), VL_GetEntryByID(), VL_GetEntryByNameN(), VL_GetEntryByNameO(), VL_ReplaceEntryN(), VL_ReplaceEntry(), VL_ListAttributesN(), VL_ListAttributes(), VL_GetAddrsU();
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 OldVLDB_to_NewVLDB(
28   struct vldbentry *source,
29   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     bzero(dest, 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 NewVLDB_to_OldVLDB(
64   struct nvldbentry *source,
65   struct vldbentry *dest,
66   afs_status_p st)
67 {
68     register int i;
69     afs_status_t tst = 0;
70     int rc = 0;
71
72     bzero(dest, sizeof(struct vldbentry));
73     strncpy(dest->name, source->name, sizeof(dest->name));
74     if (source->nServers <= OMAXNSERVERS) {
75         for (i = 0; i < source->nServers; i++) {
76             dest->serverNumber[i] = source->serverNumber[i];
77             dest->serverPartition[i] = source->serverPartition[i];
78             dest->serverFlags[i] = source->serverFlags[i];
79         }
80         dest->nServers = i;
81         for (i = 0; i < MAXTYPES; i++)
82             dest->volumeId[i] = source->volumeId[i];
83         dest->cloneId = source->cloneId;
84         dest->flags = source->flags;
85         rc = 1;
86     } else {
87         tst = VL_BADSERVER;
88     }
89
90     if (st != NULL) {
91         *st = tst;
92     }
93     return rc;
94 }
95
96 int VLDB_CreateEntry(
97   afs_cell_handle_p cellHandle,
98   struct nvldbentry *entryp,
99   afs_status_p st)
100 {
101     struct vldbentry oentry;
102     afs_status_t tst = 0;
103     int rc = 0;
104
105     do {
106         if (cellHandle->vos_new) {
107             tst = ubik_Call(VL_CreateEntryN, cellHandle->vos, 0, entryp);
108             if (tst) {
109                 if (tst == RXGEN_OPCODE) {
110                     cellHandle->vos_new = 0;
111                 }
112             } else {
113                 rc = 1;
114             }
115         } else {
116             if (NewVLDB_to_OldVLDB(entryp, &oentry, &tst)) {
117                 tst = ubik_Call(VL_CreateEntry, cellHandle->vos, 0, &oentry);
118                 if (!tst) {
119                     rc = 1;
120                 }
121             }
122         }
123     } while (tst == RXGEN_OPCODE);
124
125     if (st != NULL) {
126         *st = tst;
127     } 
128     return rc;
129 }
130
131 int VLDB_GetEntryByID(
132   afs_cell_handle_p cellHandle,
133   afs_int32   volid,
134   afs_int32 voltype,
135   struct nvldbentry *entryp,
136   afs_status_p st)
137 {
138     struct vldbentry oentry;
139     afs_status_t tst = 0;
140     int rc = 0;
141
142     do {
143         if (cellHandle->vos_new) {
144             tst = ubik_Call(VL_GetEntryByIDN, cellHandle->vos, 0, volid,
145                             voltype, entryp);
146             if (tst) {
147                 if (tst == RXGEN_OPCODE) {
148                     cellHandle->vos_new = 0;
149                 }
150             } else {
151                 rc = 1;
152             }
153         } else {
154             tst = ubik_Call(VL_GetEntryByID, cellHandle->vos, 0, volid,
155                             voltype, &oentry);
156             if (tst == 0) {
157                 rc = OldVLDB_to_NewVLDB(&oentry, entryp, &tst);
158             }
159         }
160
161     } while (tst == RXGEN_OPCODE);
162
163     if (st != NULL) {
164         *st = tst;
165     } 
166     return rc;
167 }
168
169 int VLDB_GetEntryByName(
170   afs_cell_handle_p cellHandle,
171   const char *namep,
172   struct nvldbentry *entryp,
173   afs_status_p st)
174 {
175     struct vldbentry oentry;
176     afs_status_t tst = 0;
177     int rc = 0;
178
179     do {
180         if (cellHandle->vos_new) {
181             tst = ubik_Call(VL_GetEntryByNameN, cellHandle->vos, 0, namep,
182                             entryp);
183             if (tst) {
184                 if (tst == RXGEN_OPCODE) {
185                     cellHandle->vos_new = 0;
186                 }
187             } else {
188                 rc = 1;
189             }
190         } else {
191             tst = ubik_Call(VL_GetEntryByNameO, cellHandle->vos, 0, namep,
192                             &oentry);
193             if (tst == 0) {
194                 rc = OldVLDB_to_NewVLDB(&oentry, entryp, &tst);
195             }
196         }
197
198     } while (tst == RXGEN_OPCODE);
199
200     if (st != NULL) {
201         *st = tst;
202     } 
203     return rc;
204 }
205
206 int VLDB_ReplaceEntry(
207   afs_cell_handle_p cellHandle,
208   afs_int32   volid,
209   afs_int32 voltype,
210   struct nvldbentry *entryp,
211   afs_int32   releasetype,
212   afs_status_p st)
213 {
214     struct vldbentry oentry;
215     afs_status_t tst = 0;
216     int rc = 0;
217
218     do {
219         if (cellHandle->vos_new) {
220             tst = ubik_Call(VL_ReplaceEntryN, cellHandle->vos, 0, volid, 
221                             voltype, entryp, releasetype);
222             if (tst) {
223                 if (tst == RXGEN_OPCODE) {
224                     cellHandle->vos_new = 0;
225                 }
226             } else {
227                 rc = 1;
228             }
229         } else {
230             if (NewVLDB_to_OldVLDB(entryp, &oentry, &tst)) {
231                 tst = ubik_Call(VL_ReplaceEntry, cellHandle->vos, 0, volid, 
232                                 voltype, &oentry, releasetype);
233                 if (!tst) {
234                     rc = 1;
235                 }
236             }
237         }
238     } while (tst == RXGEN_OPCODE);
239
240     if (st != NULL) {
241         *st = tst;
242     } 
243     return rc;
244 }
245
246 int VLDB_ListAttributes(
247   afs_cell_handle_p cellHandle,
248   VldbListByAttributes *attrp,
249   afs_int32  *entriesp,
250   nbulkentries *blkentriesp,
251   afs_status_p st)
252 {
253     bulkentries arrayEntries;
254     int i;
255     afs_status_t tst = 0;
256     int rc = 0;
257
258     do {
259         if (cellHandle->vos_new) {
260             tst = ubik_Call(VL_ListAttributesN, cellHandle->vos, 0, attrp,
261                             entriesp, blkentriesp);
262             if (tst) {
263                 if (tst == RXGEN_OPCODE) {
264                     cellHandle->vos_new = 0;
265                 }
266             } else {
267                 rc = 1;
268             }
269         } else {
270             memset((void *) &arrayEntries, 0, sizeof(arrayEntries));
271             tst = ubik_Call(VL_ListAttributes, cellHandle->vos, 0, attrp,
272                             entriesp, arrayEntries);
273             if (tst == 0) {
274                 blkentriesp->nbulkentries_val = (nvldbentry *) malloc(*entriesp * sizeof(*blkentriesp));
275                 if (blkentriesp->nbulkentries_val != NULL) {
276                     for(i=0;i< *entriesp;i++) {
277                         OldVLDB_to_NewVLDB((struct vldbentry *) &arrayEntries.bulkentries_val[i], (struct nvldbentry *) &blkentriesp->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 VLDB_ListAttributesN2(
298   afs_cell_handle_p cellHandle,
299   VldbListByAttributes *attrp,
300   char   *name,
301   afs_int32   thisindex,
302   afs_int32  *nentriesp,
303   nbulkentries *blkentriesp,
304   afs_int32  *nextindexp,
305   afs_status_p st)
306 {
307     int rc = 0;
308     afs_status_t tst = 0;
309
310     tst = ubik_Call(VL_ListAttributesN2, cellHandle->vos, 0,
311                      attrp, (name ? name : ""), thisindex,
312                      nentriesp, blkentriesp, nextindexp);
313     if (!tst) {
314         rc = 1;
315     }
316
317     if (st != NULL) {
318         *st = tst;
319     }
320     return rc;
321 }
322
323 int VLDB_IsSameAddrs(
324   afs_cell_handle_p cellHandle,
325   afs_int32 serv1,
326   afs_int32 serv2,
327   int *equal,
328   afs_status_p st)
329 {
330     int rc = 0;
331     afs_status_t tst = 0;
332
333     ListAddrByAttributes attrs;
334     bulkaddrs addrs;
335     afs_uint32 *addrp,
336             nentries,
337             unique,
338             i;
339     afsUUID uuid;
340
341     *equal = 0;
342
343     if (serv1 == serv2) {
344         *equal = 1;
345         rc = 1;
346         goto fail_VLDB_IsSameAddrs;
347     }
348
349     bzero(&attrs, sizeof(attrs));
350     attrs.Mask = VLADDR_IPADDR;
351     attrs.ipaddr = serv1;
352     bzero(&addrs, sizeof(addrs));
353     bzero(&uuid, sizeof(uuid));
354     tst = ubik_Call(VL_GetAddrsU, cellHandle->vos, 0, &attrs, &uuid,
355                     &unique, &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 GetVolumeInfo(
407   afs_cell_handle_p cellHandle,
408   unsigned int volid, 
409   struct nvldbentry *rentry,
410   afs_int32 *server, 
411   afs_int32 *partition, 
412   afs_int32 *voltype,
413   afs_status_p st)
414 {
415     int rc = 0;
416     afs_status_t tst;
417     int i,index = -1;
418  
419     if (!VLDB_GetEntryByID(cellHandle, volid, -1, rentry, &tst)) {
420         rc = 0;
421         goto fail_GetVolumeInfo;
422     }
423
424     if(volid == rentry->volumeId[ROVOL]){
425         *voltype = ROVOL;
426         for (i = 0; i < rentry->nServers; i++) {
427             if ( (index == -1) && (rentry->serverFlags[i] & ITSROVOL) &&
428                 !(rentry->serverFlags[i] & RO_DONTUSE) )
429                 index = i;
430         }
431         if(index == -1) {
432             tst = 1;
433             goto fail_GetVolumeInfo;
434         }
435         *server = rentry->serverNumber[index];
436         *partition = rentry->serverPartition[index];
437         rc = 1;
438         goto fail_GetVolumeInfo;
439     }
440        
441     if ((index = Lp_GetRwIndex(cellHandle, rentry, &tst))<0) {
442         goto fail_GetVolumeInfo;
443     }
444     if(volid == rentry->volumeId[RWVOL]){
445         *voltype = RWVOL;
446         *server = rentry->serverNumber[index];
447         *partition = rentry->serverPartition[index];
448     } else if(volid == rentry->volumeId[BACKVOL]){
449         *voltype = BACKVOL;
450         *server = rentry->serverNumber[index];
451         *partition = rentry->serverPartition[index];
452     }
453     rc = 1; 
454
455 fail_GetVolumeInfo:
456
457     if (st != NULL) {
458         *st = tst;
459     }
460     return rc;
461 }
462
463 /*
464  * ValidateVolumeName - validate a potential volume name
465  *
466  * PARAMETERS
467  *
468  * IN volumeName - the volume name to be validated.
469  *
470  * LOCKS
471  *
472  * No locks are obtained or released by this function
473  *
474  * RETURN CODES
475  *
476  * Returns != 0 upon successful completion.
477  */
478
479 int ValidateVolumeName(
480   const char *volumeName,
481   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 vsu_ExtractName(
520   char *rname,
521   char *name)
522 {
523     char sname[32];
524     size_t total;
525  
526     strcpy(sname,name);
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     }
534     else if((total > 7) && (!strcmp(&sname[total - 7 ],".backup"))) {
535         /*discard last 6 chars */
536         sname[total - 7] = '\0';
537         strcpy(rname,sname);
538         return 0;
539     }
540     else {
541         strncpy(rname,name,VOLSER_OLDMAXVOLNAME);
542         return -1;
543     }
544 }
545
546
547
548 /*
549  * AddressMatch - determines if an IP address matches a pattern
550  *
551  * PARAMETERS
552  *
553  * IN addrTest - the IP address to test, in either byte-order
554  * IN addrPattern - the IP address pattern, in the same byte-order
555  *
556  * LOCKS
557  *
558  * No locks are obtained or released by this function
559  *
560  * RETURN CODES
561  *
562  * Returns != 0 if the address matches the pattern specified
563  * (where 255 in any byte in the pattern indicates a wildcard).
564  */
565
566 int AddressMatch (
567     int addrTest,
568     int addrPattern)
569 {
570     int bTest;
571     int bPattern;
572
573     /* Test the high byte */
574     bTest = addrTest >> 24;
575     bPattern = addrPattern >> 24;
576     if ((bTest != bPattern) && (bPattern != 255)) {
577         return FALSE;
578     }
579
580     /* Test the next-highest byte */
581     bTest = (addrTest >> 16) & 255;
582     bPattern = (addrPattern >> 16) & 255;
583     if ((bTest != bPattern) && (bPattern != 255)) {
584         return FALSE;
585     }
586
587     /* Test the next-to-lowest byte */
588     bTest = (addrTest >> 8) & 255;
589     bPattern = (addrPattern >> 8) & 255;
590     if ((bTest != bPattern) && (bPattern != 255)) {
591         return FALSE;
592     }
593
594     /* Test the low byte */
595     bTest = addrTest & 255;
596     bPattern = addrPattern & 255;
597     if ((bTest != bPattern) && (bPattern != 255)) {
598         return FALSE;
599     }
600
601     return TRUE;
602 }
603
604
605 /*
606  * RemoveBadAddresses - (optionally) removes addresses that are better ignored
607  *
608  * PARAMETERS
609  *
610  * IN OUT totalp - the number of addresses in the addrsp structure
611  * IN OUT addrsp - a bulk array of addresses
612  *
613  * LOCKS
614  *
615  * No locks are obtained or released by this function
616  *
617  * RETURN CODES
618  *
619  * Returns != 0 upon successful completion.
620  */
621
622 static pthread_once_t badaddr_init_once = PTHREAD_ONCE_INIT;
623 static int addr_to_skip;
624
625 static void badaddr_once (void)
626 {
627
628 #ifdef AFS_NT40_ENV
629
630 #define cszREG_IGNORE_KEY "Software\\TransarcCorporation\\AFS Control Center"
631 #define cszREG_IGNORE_VALUE "IgnoreBadAddrs"
632
633     /*
634      * In order for this routine to do anything, it must first validate
635      * that the user of this machine wants this filtering to take place.
636      * There is an undocumented registry value which signifies that it's
637      * okay to filter bogus IP addresses--and, moreover, indicates
638      * the range of values which may be ignored. Check that value.
639      */
640
641     HKEY hk;
642     addr_to_skip = 0; /* don't ignore any addrs unless we find otherwise */
643     if (RegOpenKey (HKEY_LOCAL_MACHINE, cszREG_IGNORE_KEY, &hk) == 0) {
644         DWORD dwType = REG_DWORD;
645         DWORD dwSize = sizeof(addr_to_skip);
646         RegQueryValueEx (hk, cszREG_IGNORE_VALUE, 0,
647                              &dwType, (PBYTE)&addr_to_skip, &dwSize);
648         RegCloseKey (hk);
649     }
650
651 #else
652
653     /*
654      * We only support this functionality (so far) on NT; on other
655      * platforms, we'll never ignore IP addresses. If the feature
656      * is needed in the future, here's the place to add it.
657      *
658      */
659
660     addr_to_skip = 0; /* don't skip any addresses */
661
662 #endif
663
664 }
665
666 int RemoveBadAddresses(
667    afs_int32 *totalp,
668    bulkaddrs *addrsp)
669 {
670     pthread_once (&badaddr_init_once, badaddr_once);
671
672     /*
673      * If we've been requested to skip anything, addr_to_skip will be
674      * non-zero. It's actually an IP address of the form:
675      *    10.0.0.255
676      * A "255" means any value is acceptable, and any other value means
677      * the to-be-skipped address must match that value.
678      */
679
680     if (addr_to_skip && addrsp && addrsp->bulkaddrs_val) {
681         size_t iiWrite = 0;
682         size_t iiRead = 0;
683         for ( ; iiRead < addrsp->bulkaddrs_len; ++iiRead) {
684
685             /*
686              * Check this IP address to see if it should be skipped.
687              */
688
689             if (!AddressMatch(addrsp->bulkaddrs_val[iiRead],addr_to_skip)) {
690
691                 /*
692                  * The address is okay; make sure it stays in the list.
693                  */
694
695                 if (iiWrite != iiRead) {
696                     addrsp->bulkaddrs_val[iiWrite] =
697                     addrsp->bulkaddrs_val[iiRead];
698                 }
699
700                 ++iiWrite;
701             }
702         }
703         *totalp = (afs_int32)iiWrite;
704         addrsp->bulkaddrs_len = iiWrite;
705     }
706
707     return TRUE;
708 }
709