ticket-2618-patches-20031207
[openafs.git] / src / volser / vsutils.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 RCSID
14     ("$Header$");
15
16 #include <afs/stds.h>
17 #ifdef AFS_NT40_ENV
18 #include <fcntl.h>
19 #include <winsock2.h>
20 #else
21 #include <sys/types.h>
22 #include <sys/file.h>
23 #include <netdb.h>
24 #include <netinet/in.h>
25 #endif /* AFS_NT40_ENV */
26 #include <sys/stat.h>
27 #ifdef AFS_AIX_ENV
28 #include <sys/statfs.h>
29 #endif
30
31 #ifdef HAVE_STRING_H
32 #include <string.h>
33 #else
34 #ifdef HAVE_STRINGS_H
35 #include <strings.h>
36 #endif
37 #endif
38
39 #include <errno.h>
40 #include <lock.h>
41 #include <rx/xdr.h>
42 #include <rx/rx.h>
43 #include <rx/rx_globals.h>
44 #include <afs/nfs.h>
45 #include <afs/vlserver.h>
46 #include <afs/auth.h>
47 #include <afs/cellconfig.h>
48 #include <afs/keys.h>
49 #include <ubik.h>
50 #include <afs/afsint.h>
51 #include <afs/cmd.h>
52 #include <rx/rxkad.h>
53 #include "volser.h"
54 #include "volint.h"
55 #include "lockdata.h"
56
57 struct ubik_client *cstruct;
58 static rxkad_level vsu_rxkad_level = rxkad_clear;
59
60 static void
61 ovlentry_to_nvlentry(oentryp, nentryp)
62      struct vldbentry *oentryp;
63      struct nvldbentry *nentryp;
64 {
65     register int i;
66
67     memset(nentryp, 0, sizeof(struct nvldbentry));
68     strncpy(nentryp->name, oentryp->name, sizeof(nentryp->name));
69     for (i = 0; i < oentryp->nServers; i++) {
70         nentryp->serverNumber[i] = oentryp->serverNumber[i];
71         nentryp->serverPartition[i] = oentryp->serverPartition[i];
72         nentryp->serverFlags[i] = oentryp->serverFlags[i];
73     }
74     nentryp->nServers = oentryp->nServers;
75     for (i = 0; i < MAXTYPES; i++)
76         nentryp->volumeId[i] = oentryp->volumeId[i];
77     nentryp->cloneId = oentryp->cloneId;
78     nentryp->flags = oentryp->flags;
79 }
80
81 static
82 nvlentry_to_ovlentry(nentryp, oentryp)
83      struct nvldbentry *nentryp;
84      struct vldbentry *oentryp;
85 {
86     register int i;
87
88     memset(oentryp, 0, sizeof(struct vldbentry));
89     strncpy(oentryp->name, nentryp->name, sizeof(oentryp->name));
90     if (nentryp->nServers > OMAXNSERVERS) {
91         /*
92          * The alternative is to store OMAXSERVERS but it's always better
93          * to know what's going on...
94          */
95         return VL_BADSERVER;
96     }
97     for (i = 0; i < nentryp->nServers; i++) {
98         oentryp->serverNumber[i] = nentryp->serverNumber[i];
99         oentryp->serverPartition[i] = nentryp->serverPartition[i];
100         oentryp->serverFlags[i] = nentryp->serverFlags[i];
101     }
102     oentryp->nServers = i;
103     for (i = 0; i < MAXTYPES; i++)
104         oentryp->volumeId[i] = nentryp->volumeId[i];
105     oentryp->cloneId = nentryp->cloneId;
106     oentryp->flags = nentryp->flags;
107     return 0;
108 }
109
110 static int newvlserver = 0;
111
112 VLDB_CreateEntry(entryp)
113      struct nvldbentry *entryp;
114 {
115     struct vldbentry oentry;
116     register int code;
117
118     if (newvlserver == 1) {
119       tryold:
120         code = nvlentry_to_ovlentry(entryp, &oentry);
121         if (code)
122             return code;
123         code = ubik_Call(VL_CreateEntry, cstruct, 0, &oentry);
124         return code;
125     }
126     code = ubik_Call(VL_CreateEntryN, cstruct, 0, entryp);
127     if (!newvlserver) {
128         if (code == RXGEN_OPCODE) {
129             newvlserver = 1;    /* Doesn't support new interface */
130             goto tryold;
131         } else if (!code) {
132             newvlserver = 2;
133         }
134     }
135     return code;
136 }
137
138 VLDB_GetEntryByID(volid, voltype, entryp)
139      afs_int32 volid, voltype;
140      struct nvldbentry *entryp;
141 {
142     struct vldbentry oentry;
143     register int code;
144
145     if (newvlserver == 1) {
146       tryold:
147         code =
148             ubik_Call(VL_GetEntryByID, cstruct, 0, volid, voltype, &oentry);
149         if (!code)
150             ovlentry_to_nvlentry(&oentry, entryp);
151         return code;
152     }
153     code = ubik_Call(VL_GetEntryByIDN, cstruct, 0, volid, voltype, entryp);
154     if (!newvlserver) {
155         if (code == RXGEN_OPCODE) {
156             newvlserver = 1;    /* Doesn't support new interface */
157             goto tryold;
158         } else if (!code) {
159             newvlserver = 2;
160         }
161     }
162     return code;
163 }
164
165 VLDB_GetEntryByName(namep, entryp)
166      char *namep;
167      struct nvldbentry *entryp;
168 {
169     struct vldbentry oentry;
170     register int code;
171
172     if (newvlserver == 1) {
173       tryold:
174         code = ubik_Call(VL_GetEntryByNameO, cstruct, 0, namep, &oentry);
175         if (!code)
176             ovlentry_to_nvlentry(&oentry, entryp);
177         return code;
178     }
179     code = ubik_Call(VL_GetEntryByNameN, cstruct, 0, namep, entryp);
180     if (!newvlserver) {
181         if (code == RXGEN_OPCODE) {
182             newvlserver = 1;    /* Doesn't support new interface */
183             goto tryold;
184         } else if (!code) {
185             newvlserver = 2;
186         }
187     }
188     return code;
189 }
190
191 VLDB_ReplaceEntry(volid, voltype, entryp, releasetype)
192      afs_int32 volid, voltype, releasetype;
193      struct nvldbentry *entryp;
194 {
195     struct vldbentry oentry;
196     register int code;
197
198     if (newvlserver == 1) {
199       tryold:
200         code = nvlentry_to_ovlentry(entryp, &oentry);
201         if (code)
202             return code;
203         code =
204             ubik_Call(VL_ReplaceEntry, cstruct, 0, volid, voltype, &oentry,
205                       releasetype);
206         return code;
207     }
208     code =
209         ubik_Call(VL_ReplaceEntryN, cstruct, 0, volid, voltype, entryp,
210                   releasetype);
211     if (!newvlserver) {
212         if (code == RXGEN_OPCODE) {
213             newvlserver = 1;    /* Doesn't support new interface */
214             goto tryold;
215         } else if (!code) {
216             newvlserver = 2;
217         }
218     }
219     return code;
220 }
221
222
223
224 VLDB_ListAttributes(attrp, entriesp, blkentriesp)
225      VldbListByAttributes *attrp;
226      afs_int32 *entriesp;
227      nbulkentries *blkentriesp;
228 {
229     bulkentries arrayEntries;
230     register int code, i;
231
232     if (newvlserver == 1) {
233       tryold:
234         memset(&arrayEntries, 0, sizeof(arrayEntries)); /*initialize to hint the stub  to alloc space */
235         code =
236             ubik_Call(VL_ListAttributes, cstruct, 0, attrp, entriesp,
237                       &arrayEntries);
238         if (!code) {
239             blkentriesp->nbulkentries_val =
240                 (nvldbentry *) malloc(*entriesp * sizeof(struct nvldbentry));
241             for (i = 0; i < *entriesp; i++) {   /* process each entry */
242                 ovlentry_to_nvlentry(&arrayEntries.bulkentries_val[i],
243                                      &blkentriesp->nbulkentries_val[i]);
244             }
245         }
246         if (arrayEntries.bulkentries_val)
247             free(arrayEntries.bulkentries_val);
248         return code;
249     }
250     code =
251         ubik_Call(VL_ListAttributesN, cstruct, 0, attrp, entriesp,
252                   blkentriesp);
253     if (!newvlserver) {
254         if (code == RXGEN_OPCODE) {
255             newvlserver = 1;    /* Doesn't support new interface */
256             goto tryold;
257         } else if (!code) {
258             newvlserver = 2;
259         }
260     }
261     return code;
262 }
263
264 VLDB_ListAttributesN2(attrp, name, thisindex, nentriesp, blkentriesp,
265                       nextindexp)
266      VldbListByAttributes *attrp;
267      char *name;
268      afs_int32 thisindex;
269      afs_int32 *nentriesp;
270      nbulkentries *blkentriesp;
271      afs_int32 *nextindexp;
272 {
273     afs_int32 code;
274
275     code =
276         ubik_Call(VL_ListAttributesN2, cstruct, 0, attrp, (name ? name : ""),
277                   thisindex, nentriesp, blkentriesp, nextindexp);
278     return code;
279 }
280
281
282 static int vlserverv4 = -1;
283 struct cacheips {
284     afs_int32 server;
285     afs_int32 count;
286     afs_uint32 addrs[16];
287 };
288 /*
289  * Increase cache size.  This avoids high CPU usage by the vlserver
290  * in environments where there are more than 16 fileservers in the
291  * cell.
292  */
293 #define GETADDRUCACHESIZE             64
294 struct cacheips cacheips[GETADDRUCACHESIZE];
295 int cacheip_index = 0;
296
297 VLDB_IsSameAddrs(serv1, serv2, errorp)
298      afs_int32 serv1, serv2, *errorp;
299 {
300     register int code;
301     ListAddrByAttributes attrs;
302     bulkaddrs addrs;
303     afs_uint32 *addrp, nentries, unique, i, j, f1, f2;
304     afsUUID uuid;
305     static int initcache = 0;
306
307     *errorp = 0;
308
309     if (serv1 == serv2)
310         return 1;
311     if (vlserverv4 == 1) {
312         return 0;
313     }
314     if (!initcache) {
315         for (i = 0; i < GETADDRUCACHESIZE; i++) {
316             cacheips[i].server = cacheips[i].count = 0;
317         }
318         initcache = 1;
319     }
320
321     /* See if it's cached */
322     for (i = 0; i < GETADDRUCACHESIZE; i++) {
323         f1 = f2 = 0;
324         for (j = 0; j < cacheips[i].count; j++) {
325             if (serv1 == cacheips[i].addrs[j])
326                 f1 = 1;
327             else if (serv2 == cacheips[i].addrs[j])
328                 f2 = 1;
329
330             if (f1 && f2)
331                 return 1;
332         }
333         if (f1 || f2)
334             return 0;
335         if (cacheips[i].server == serv1)
336             return 0;
337     }
338
339     memset(&attrs, 0, sizeof(attrs));
340     attrs.Mask = VLADDR_IPADDR;
341     attrs.ipaddr = serv1;
342     memset(&addrs, 0, sizeof(addrs));
343     memset(&uuid, 0, sizeof(uuid));
344     code =
345         ubik_Call(VL_GetAddrsU, cstruct, 0, &attrs, &uuid, &unique, &nentries,
346                   &addrs);
347     if (vlserverv4 == -1) {
348         if (code == RXGEN_OPCODE) {
349             vlserverv4 = 1;     /* Doesn't support new interface */
350             return 0;
351         } else if (!code) {
352             vlserverv4 = 2;
353         }
354     }
355     if (code == VL_NOENT)
356         return 0;
357     if (code) {
358         *errorp = code;
359         return 0;
360     }
361
362     code = 0;
363     if (nentries > GETADDRUCACHESIZE)
364         nentries = GETADDRUCACHESIZE;   /* safety check; should not happen */
365     if (++cacheip_index >= GETADDRUCACHESIZE)
366         cacheip_index = 0;
367     cacheips[cacheip_index].server = serv1;
368     cacheips[cacheip_index].count = nentries;
369     addrp = addrs.bulkaddrs_val;
370     for (i = 0; i < nentries; i++, addrp++) {
371         cacheips[cacheip_index].addrs[i] = *addrp;
372         if (serv2 == *addrp) {
373             code = 1;
374         }
375     }
376     return code;
377 }
378
379
380 #ifdef  notdef
381 afs_int32
382 subik_Call(aproc, aclient, aflags, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10,
383            p11, p12, p13, p14, p15, p16)
384      register struct ubik_client *aclient;
385      int (*aproc) ();
386      afs_int32 aflags;
387      afs_int32 p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14,
388          p15, p16;
389 {
390     struct vldbentry vldbentry;
391     register int code, (*nproc) ();
392
393     if (newvlserver == 1) {
394     }
395     code =
396         ubik_Call(aproc, aclient, aflags, p1, p2, p3, p4, p5, p6, p7, p8, p9,
397                   p10, p11, p12, p13, p14, p15, p16);
398     if (!newvlserver) {
399         if (code == RXGEN_OPCODE) {
400             newvlserver = 1;    /* Doesn't support new interface */
401         } else if (!code) {
402             newvlserver = 2;
403         }
404     }
405 }
406 #endif /* notdef */
407
408
409 /*
410   Set encryption.  If 'cryptflag' is nonzero, encrpytion is turned on
411   for authenticated connections; if zero, encryption is turned off.
412   Calling this function always results in a level of at least rxkad_auth;
413   to get a rxkad_clear connection, simply don't call this.
414 */
415 void
416 vsu_SetCrypt(cryptflag)
417      int cryptflag;
418 {
419     if (cryptflag) {
420         vsu_rxkad_level = rxkad_crypt;
421     } else {
422         vsu_rxkad_level = rxkad_auth;
423     }
424 }
425
426
427 /*
428   Get the appropriate type of ubik client structure out from the system.
429 */
430 afs_int32
431 vsu_ClientInit(noAuthFlag, confDir, cellName, sauth, uclientp, secproc)
432      int noAuthFlag;
433      int (*secproc) ();
434      char *cellName;
435      struct ubik_client **uclientp;
436      char *confDir;
437      afs_int32 sauth;
438 {
439     afs_int32 code, scIndex, i;
440     struct afsconf_cell info;
441     struct afsconf_dir *tdir;
442     struct ktc_principal sname;
443     struct ktc_token ttoken;
444     struct rx_securityClass *sc;
445     static struct rx_connection *serverconns[VLDB_MAXSERVERS];
446     char cellstr[64];
447
448
449     code = rx_Init(0);
450     if (code) {
451         fprintf(STDERR, "vsu_ClientInit: could not initialize rx.\n");
452         return code;
453     }
454     rx_SetRxDeadTime(90);
455
456     if (sauth) {                /* -localauth */
457         tdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
458         if (!tdir) {
459             fprintf(STDERR,
460                     "vsu_ClientInit: Could not process files in configuration directory (%s).\n",
461                     AFSDIR_SERVER_ETC_DIRPATH);
462             return -1;
463         }
464         code = afsconf_ClientAuth(tdir, &sc, &scIndex); /* sets sc,scIndex */
465         if (code) {
466             fprintf(STDERR,
467                     "vsu_ClientInit: Could not get security object for -localAuth\n");
468             return -1;
469         }
470         code =
471             afsconf_GetCellInfo(tdir, tdir->cellName, AFSCONF_VLDBSERVICE,
472                                 &info);
473         if (code) {
474             fprintf(STDERR,
475                     "vsu_ClientInit: can't find cell %s's hosts in %s/%s\n",
476                     cellName, AFSDIR_SERVER_ETC_DIRPATH,
477                     AFSDIR_CELLSERVDB_FILE);
478             exit(1);
479         }
480     } else {                    /* not -localauth */
481         tdir = afsconf_Open(confDir);
482         if (!tdir) {
483             fprintf(STDERR,
484                     "vsu_ClientInit: Could not process files in configuration directory (%s).\n",
485                     confDir);
486             return -1;
487         }
488
489         if (!cellName) {
490             code = afsconf_GetLocalCell(tdir, cellstr, sizeof(cellstr));
491             if (code) {
492                 fprintf(STDERR,
493                         "vsu_ClientInit: can't get local cellname, check %s/%s\n",
494                         confDir, AFSDIR_THISCELL_FILE);
495                 exit(1);
496             }
497             cellName = cellstr;
498         }
499
500         code =
501             afsconf_GetCellInfo(tdir, cellName, AFSCONF_VLDBSERVICE, &info);
502         if (code) {
503             fprintf(STDERR,
504                     "vsu_ClientInit: can't find cell %s's hosts in %s/%s\n",
505                     cellName, confDir, AFSDIR_CELLSERVDB_FILE);
506             exit(1);
507         }
508         if (noAuthFlag)         /* -noauth */
509             scIndex = 0;
510         else {                  /* not -noauth */
511             strcpy(sname.cell, info.name);
512             sname.instance[0] = 0;
513             strcpy(sname.name, "afs");
514             code = ktc_GetToken(&sname, &ttoken, sizeof(ttoken), NULL);
515             if (code) {         /* did not get ticket */
516                 fprintf(STDERR,
517                         "vsu_ClientInit: Could not get afs tokens, running unauthenticated.\n");
518                 scIndex = 0;
519             } else {            /* got a ticket */
520                 scIndex = 2;
521                 if ((ttoken.kvno < 0) || (ttoken.kvno > 255)) {
522                     fprintf(STDERR,
523                             "vsu_ClientInit: funny kvno (%d) in ticket, proceeding\n",
524                             ttoken.kvno);
525                 }
526             }
527         }
528
529         switch (scIndex) {
530         case 0:
531             sc = rxnull_NewClientSecurityObject();
532             break;
533         case 2:
534             sc = rxkad_NewClientSecurityObject(vsu_rxkad_level,
535                                                &ttoken.sessionKey,
536                                                ttoken.kvno, ttoken.ticketLen,
537                                                ttoken.ticket);
538             break;
539         default:
540             fprintf(STDERR, "vsu_ClientInit: unsupported security index %d\n",
541                     scIndex);
542             exit(1);
543             break;
544         }
545     }
546
547     afsconf_Close(tdir);
548
549     if (secproc)                /* tell UV module about default authentication */
550         (*secproc) (sc, scIndex);
551     if (info.numServers > VLDB_MAXSERVERS) {
552         fprintf(STDERR,
553                 "vsu_ClientInit: info.numServers=%d (> VLDB_MAXSERVERS=%d)\n",
554                 info.numServers, VLDB_MAXSERVERS);
555         exit(1);
556     }
557     for (i = 0; i < info.numServers; i++) {
558         serverconns[i] =
559             rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
560                              info.hostAddr[i].sin_port, USER_SERVICE_ID, sc,
561                              scIndex);
562     }
563     *uclientp = 0;
564     code = ubik_ClientInit(serverconns, uclientp);
565     if (code) {
566         fprintf(STDERR, "vsu_ClientInit: ubik client init failed.\n");
567         return code;
568     }
569     return 0;
570 }
571
572
573 /*extract the name of volume <name> without readonly or backup suffixes
574  * and return the result as <rname>.
575  */
576 int
577 vsu_ExtractName(rname, name)
578      char rname[], name[];
579 {
580     char sname[VOLSER_OLDMAXVOLNAME + 1];
581     int total;
582
583     strncpy(sname, name, sizeof(sname));
584     sname[sizeof(sname) - 1] = '\0';
585     total = strlen(sname);
586     if (!strcmp(&sname[total - 9], ".readonly")) {
587         /*discard the last 8 chars */
588         sname[total - 9] = '\0';
589         strcpy(rname, sname);
590         return 0;
591     } else if (!strcmp(&sname[total - 7], ".backup")) {
592         /*discard last 6 chars */
593         sname[total - 7] = '\0';
594         strcpy(rname, sname);
595         return 0;
596     } else {
597         strncpy(rname, name, VOLSER_OLDMAXVOLNAME);
598         rname[VOLSER_OLDMAXVOLNAME] = '\0';
599         return -1;
600     }
601 }
602
603
604 /* returns 0 if failed */
605 afs_uint32
606 vsu_GetVolumeID(astring, acstruct, errp)
607      struct ubik_client *acstruct;
608      afs_int32 *errp;
609      char *astring;
610 {
611     afs_uint32 tc, value;
612
613     char *str, *ptr, volname[VOLSER_OLDMAXVOLNAME + 1];
614     int tryname, curval;
615     struct nvldbentry entry;
616     afs_int32 vcode = 0;
617     int total;
618
619     *errp = 0;
620     total = strlen(astring);
621     str = astring;
622     ptr = astring;
623     tryname = 0;
624     while ((curval = *str++)) {
625         if (curval < '0' || curval > '9')
626             tryname = 1;
627     }
628
629     if (tryname) {
630         vsu_ExtractName(volname, astring);
631         vcode = VLDB_GetEntryByName(volname, &entry);
632         if (!vcode) {
633             if (!strcmp(&astring[total - 9], ".readonly"))
634                 return entry.volumeId[ROVOL];
635             else if ((!strcmp(&astring[total - 7], ".backup")))
636                 return entry.volumeId[BACKVOL];
637             else
638                 return (entry.volumeId[RWVOL]);
639         } else {
640             *errp = vcode;
641             return 0;           /* can't find volume */
642         }
643     }
644
645     value = 0;
646     while ((tc = *astring++)) {
647         if (tc & 0x80) {
648             if (!tryname)
649                 fprintf(STDERR, "goofed in volid \n");
650             else {
651                 fprintf(STDERR, "Could not get entry from vldb for %s\n",
652                         ptr);
653                 PrintError("", vcode);
654             }
655             *errp = EINVAL;
656             return 0;
657         }
658         if (tc < '0' || tc > '9') {
659             if (!tryname)
660                 fprintf(STDERR,
661                         "internal error: out of range char in vol ID\n");
662             else {
663                 fprintf(STDERR, "Could not get entry from vldb for %s\n",
664                         ptr);
665                 PrintError("", vcode);
666             }
667             *errp = ERANGE;
668             return 0;
669         }
670         value *= 10;
671         value += (tc - '0');
672     }
673     return value;
674 }