Import Upstream version 1.8.5
[hcoop/debian/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 }