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