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