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