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