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