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