13c7fd50b017dc2c7f64d3e5d7bf43d6ce769f7a
[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 #include <roken.h>
14
15 #include <afs/stds.h>
16 #include <string.h>
17 #include <ctype.h>
18 #ifdef AFS_NT40_ENV
19 #include <fcntl.h>
20 #include <winsock2.h>
21 #else
22 #include <sys/types.h>
23 #include <sys/file.h>
24 #include <netdb.h>
25 #include <netinet/in.h>
26 #endif /* AFS_NT40_ENV */
27 #include <sys/stat.h>
28 #ifdef AFS_AIX_ENV
29 #include <sys/statfs.h>
30 #endif
31
32 #include <errno.h>
33 #include <lock.h>
34 #include <rx/xdr.h>
35 #include <rx/rx.h>
36 #include <rx/rx_globals.h>
37 #include <afs/nfs.h>
38 #include <afs/vlserver.h>
39 #include <afs/cellconfig.h>
40 #include <afs/keys.h>
41 #include <ubik.h>
42 #include <afs/afsint.h>
43 #include <afs/cmd.h>
44 #include <rx/rxkad.h>
45 #include "volser.h"
46 #include "volint.h"
47 #include "lockdata.h"
48
49 #include "vsutils_prototypes.h"
50
51 struct ubik_client *cstruct;
52 static rxkad_level vsu_rxkad_level = rxkad_clear;
53
54 static void
55 ovlentry_to_nvlentry(struct vldbentry *oentryp,
56                      struct nvldbentry *nentryp)
57 {
58     int i;
59
60     memset(nentryp, 0, sizeof(struct nvldbentry));
61     strncpy(nentryp->name, oentryp->name, sizeof(nentryp->name));
62     for (i = 0; i < oentryp->nServers; i++) {
63         nentryp->serverNumber[i] = oentryp->serverNumber[i];
64         nentryp->serverPartition[i] = oentryp->serverPartition[i];
65         nentryp->serverFlags[i] = oentryp->serverFlags[i];
66     }
67     nentryp->nServers = oentryp->nServers;
68     for (i = 0; i < MAXTYPES; i++)
69         nentryp->volumeId[i] = oentryp->volumeId[i];
70     nentryp->cloneId = oentryp->cloneId;
71     nentryp->flags = oentryp->flags;
72 }
73
74 static int
75 nvlentry_to_ovlentry(struct nvldbentry *nentryp,
76                      struct vldbentry *oentryp)
77 {
78     int i;
79
80     memset(oentryp, 0, sizeof(struct vldbentry));
81     strncpy(oentryp->name, nentryp->name, sizeof(oentryp->name));
82     if (nentryp->nServers > OMAXNSERVERS) {
83         /*
84          * The alternative is to store OMAXSERVERS but it's always better
85          * to know what's going on...
86          */
87         return VL_BADSERVER;
88     }
89     for (i = 0; i < nentryp->nServers; i++) {
90         oentryp->serverNumber[i] = nentryp->serverNumber[i];
91         oentryp->serverPartition[i] = nentryp->serverPartition[i];
92         oentryp->serverFlags[i] = nentryp->serverFlags[i];
93     }
94     oentryp->nServers = i;
95     for (i = 0; i < MAXTYPES; i++)
96         oentryp->volumeId[i] = nentryp->volumeId[i];
97     oentryp->cloneId = nentryp->cloneId;
98     oentryp->flags = nentryp->flags;
99     return 0;
100 }
101
102 enum _vlserver_type {
103     vltype_unknown = 0,
104     vltype_old = 1,
105     vltype_new = 2,
106     vltype_uuid = 3
107 };
108
109 static enum _vlserver_type newvlserver = vltype_unknown;
110
111 int
112 VLDB_CreateEntry(struct nvldbentry *entryp)
113 {
114     struct vldbentry oentry;
115     int code;
116
117     if (newvlserver == vltype_old) {
118       tryold:
119         code = nvlentry_to_ovlentry(entryp, &oentry);
120         if (code)
121             return code;
122         code = ubik_VL_CreateEntry(cstruct, 0, &oentry);
123         return code;
124     }
125     code = ubik_VL_CreateEntryN(cstruct, 0, entryp);
126     if (newvlserver == vltype_unknown) {
127         if (code == RXGEN_OPCODE) {
128             newvlserver = vltype_old;   /* Doesn't support new interface */
129             goto tryold;
130         } else if (!code) {
131             newvlserver = vltype_new;
132         }
133     }
134     return code;
135 }
136
137 int
138 VLDB_GetEntryByID(afs_uint32 volid, afs_int32 voltype, struct nvldbentry *entryp)
139 {
140     struct vldbentry oentry;
141     int code;
142
143     if (newvlserver == vltype_old) {
144       tryold:
145         code =
146             ubik_VL_GetEntryByID(cstruct, 0, volid, voltype, &oentry);
147         if (!code)
148             ovlentry_to_nvlentry(&oentry, entryp);
149         return code;
150     }
151     code = ubik_VL_GetEntryByIDN(cstruct, 0, volid, voltype, entryp);
152     if (newvlserver == vltype_unknown) {
153         if (code == RXGEN_OPCODE) {
154             newvlserver = vltype_old;   /* Doesn't support new interface */
155             goto tryold;
156         } else if (!code) {
157             newvlserver = vltype_new;
158         }
159     }
160     return code;
161 }
162
163 int
164 VLDB_GetEntryByName(char *namep, struct nvldbentry *entryp)
165 {
166     struct vldbentry oentry;
167     int code;
168
169     if (newvlserver == vltype_old) {
170       tryold:
171         code = ubik_VL_GetEntryByNameO(cstruct, 0, namep, &oentry);
172         if (!code)
173             ovlentry_to_nvlentry(&oentry, entryp);
174         return code;
175     }
176     code = ubik_VL_GetEntryByNameN(cstruct, 0, namep, entryp);
177     if (newvlserver == vltype_unknown) {
178         if (code == RXGEN_OPCODE) {
179             newvlserver = vltype_old;   /* Doesn't support new interface */
180             goto tryold;
181         } else if (!code) {
182             newvlserver = vltype_new;
183         }
184     }
185     return code;
186 }
187
188 int
189 VLDB_ReplaceEntry(afs_uint32 volid, afs_int32 voltype, struct nvldbentry *entryp, afs_int32 releasetype)
190 {
191     struct vldbentry oentry;
192     int code;
193
194     if (newvlserver == vltype_old) {
195       tryold:
196         code = nvlentry_to_ovlentry(entryp, &oentry);
197         if (code)
198             return code;
199         code =
200             ubik_VL_ReplaceEntry(cstruct, 0, volid, voltype, &oentry,
201                       releasetype);
202         return code;
203     }
204     code =
205         ubik_VL_ReplaceEntryN(cstruct, 0, volid, voltype, entryp,
206                   releasetype);
207     if (newvlserver == vltype_unknown) {
208         if (code == RXGEN_OPCODE) {
209             newvlserver = vltype_old;   /* Doesn't support new interface */
210             goto tryold;
211         } else if (!code) {
212             newvlserver = vltype_new;
213         }
214     }
215     return code;
216 }
217
218 static void
219 convertBulkToNBulk(bulkentries *bulk, nbulkentries *nbulk) {
220     int i;
221
222     if (bulk->bulkentries_len == 0)
223         return;
224
225     nbulk->nbulkentries_len = bulk->bulkentries_len;
226     nbulk->nbulkentries_val =
227         xdr_alloc(bulk->bulkentries_len * sizeof(struct nvldbentry));
228
229     for (i = 0; i < bulk->bulkentries_len; i++) {
230         ovlentry_to_nvlentry(&bulk->bulkentries_val[i],
231                              &nbulk->nbulkentries_val[i]);
232     }
233 }
234
235 int
236 VLDB_ListAttributes(VldbListByAttributes *attrp,
237                     afs_int32 *entriesp,
238                     nbulkentries *blkentriesp)
239 {
240     bulkentries arrayEntries;
241     int code;
242
243     if (newvlserver == vltype_old) {
244       tryold:
245         memset(&arrayEntries, 0, sizeof(arrayEntries));
246         code =
247             ubik_VL_ListAttributes(cstruct, 0, attrp, entriesp,
248                       &arrayEntries);
249
250         if (code)
251             return code;
252
253         /* Ensure the number of entries claimed matches the no. returned */
254         if (*entriesp < 0)
255             *entriesp = 0;
256         if (*entriesp > arrayEntries.bulkentries_len)
257             *entriesp = arrayEntries.bulkentries_len;
258
259         convertBulkToNBulk(&arrayEntries, blkentriesp);
260
261         xdr_free((xdrproc_t) xdr_bulkentries, &arrayEntries);
262         return code;
263     }
264     code =
265         ubik_VL_ListAttributesN(cstruct, 0, attrp, entriesp, blkentriesp);
266     if (newvlserver == vltype_unknown) {
267         if (code == RXGEN_OPCODE) {
268             newvlserver = vltype_old;   /* Doesn't support new interface */
269             goto tryold;
270         } else if (!code) {
271             newvlserver = vltype_new;
272         }
273     }
274
275     /* Ensure the number of entries claimed matches the no. returned */
276     if (*entriesp < 0)
277         *entriesp = 0;
278     if (*entriesp > blkentriesp->nbulkentries_len)
279         *entriesp = blkentriesp->nbulkentries_len;
280
281     return code;
282 }
283
284 int
285 VLDB_ListAttributesN2(VldbListByAttributes *attrp,
286                       char *name,
287                       afs_int32 thisindex,
288                       afs_int32 *nentriesp,
289                       nbulkentries *blkentriesp,
290                       afs_int32 *nextindexp)
291 {
292     afs_int32 code = RXGEN_OPCODE;
293
294     if (newvlserver != vltype_old) {
295         code =
296             ubik_VL_ListAttributesN2(cstruct, 0, attrp, (name ? name : ""),
297                                      thisindex, nentriesp, blkentriesp, nextindexp);
298         if (code)
299             return code;
300
301         /* Ensure the number of entries claimed matches the no. returned */
302         if (*nentriesp < 0)
303             *nentriesp = 0;
304         if (*nentriesp > blkentriesp->nbulkentries_len)
305             *nentriesp = blkentriesp->nbulkentries_len;
306     }
307     return code;
308 }
309
310 struct cacheips {
311     afs_uint32 server;
312     afs_int32 count;
313     afs_uint32 addrs[16];
314 };
315 /*
316  * Increase cache size.  This avoids high CPU usage by the vlserver
317  * in environments where there are more than 16 fileservers in the
318  * cell.
319  */
320 #define GETADDRUCACHESIZE             64
321 struct cacheips cacheips[GETADDRUCACHESIZE];
322 int cacheip_index = 0;
323
324 int
325 VLDB_IsSameAddrs(afs_uint32 serv1, afs_uint32 serv2, afs_int32 *errorp)
326 {
327     int code;
328     ListAddrByAttributes attrs;
329     bulkaddrs addrs;
330     afs_uint32 *addrp, i, j, f1, f2;
331     afs_int32 unique, nentries;
332     afsUUID uuid;
333     static int initcache = 0;
334
335     *errorp = 0;
336
337     if (serv1 == serv2)
338         return 1;
339     if (newvlserver == vltype_old || newvlserver == vltype_new) {
340         return 0;
341     }
342     if (!initcache) {
343         for (i = 0; i < GETADDRUCACHESIZE; i++) {
344             cacheips[i].server = cacheips[i].count = 0;
345         }
346         initcache = 1;
347     }
348
349     /* See if it's cached */
350     for (i = 0; i < GETADDRUCACHESIZE; i++) {
351         f1 = f2 = 0;
352         for (j = 0; j < cacheips[i].count; j++) {
353             if (serv1 == cacheips[i].addrs[j])
354                 f1 = 1;
355             else if (serv2 == cacheips[i].addrs[j])
356                 f2 = 1;
357
358             if (f1 && f2)
359                 return 1;
360         }
361         if (f1 || f2)
362             return 0;
363         if (cacheips[i].server == serv1)
364             return 0;
365     }
366
367     memset(&attrs, 0, sizeof(attrs));
368     attrs.Mask = VLADDR_IPADDR;
369     attrs.ipaddr = serv1;
370     memset(&addrs, 0, sizeof(addrs));
371     memset(&uuid, 0, sizeof(uuid));
372     code =
373         ubik_VL_GetAddrsU(cstruct, 0, &attrs, &uuid, &unique, &nentries,
374                   &addrs);
375     if (newvlserver == vltype_unknown) {
376         if (code == RXGEN_OPCODE) {
377             return 0;
378         } else if (!code) {
379             newvlserver = vltype_uuid;
380         }
381     }
382     if (code == VL_NOENT)
383         return 0;
384     if (code) {
385         *errorp = code;
386         return 0;
387     }
388
389     code = 0;
390     if (nentries > GETADDRUCACHESIZE)
391         nentries = GETADDRUCACHESIZE;   /* safety check; should not happen */
392     if (++cacheip_index >= GETADDRUCACHESIZE)
393         cacheip_index = 0;
394     cacheips[cacheip_index].server = serv1;
395     cacheips[cacheip_index].count = nentries;
396     addrp = addrs.bulkaddrs_val;
397     for (i = 0; i < nentries; i++, addrp++) {
398         cacheips[cacheip_index].addrs[i] = *addrp;
399         if (serv2 == *addrp) {
400             code = 1;
401         }
402     }
403     return code;
404 }
405
406
407 /*
408   Set encryption.  If 'cryptflag' is nonzero, encrpytion is turned on
409   for authenticated connections; if zero, encryption is turned off.
410   Calling this function always results in a level of at least rxkad_auth;
411   to get a rxkad_clear connection, simply don't call this.
412 */
413 void
414 vsu_SetCrypt(int cryptflag)
415 {
416     if (cryptflag) {
417         vsu_rxkad_level = rxkad_crypt;
418     } else {
419         vsu_rxkad_level = rxkad_auth;
420     }
421 }
422
423
424 /*
425   Get the appropriate type of ubik client structure out from the system.
426 */
427 afs_int32
428 vsu_ClientInit(int noAuthFlag, const char *confDir, char *cellName, afs_int32 sauth,
429                struct ubik_client **uclientp,
430                int (*secproc)(struct rx_securityClass *, afs_int32))
431 {
432     return ugen_ClientInit(noAuthFlag, confDir, cellName, sauth, uclientp,
433                            secproc, "vsu_ClientInit", vsu_rxkad_level,
434                            VLDB_MAXSERVERS, AFSCONF_VLDBSERVICE, 90,
435                            0, 0, USER_SERVICE_ID);
436 }
437
438
439 /*extract the name of volume <name> without readonly or backup suffixes
440  * and return the result as <rname>.
441  */
442 int
443 vsu_ExtractName(char rname[], char name[])
444 {
445     char sname[VOLSER_OLDMAXVOLNAME + 1];
446     int total;
447
448     strncpy(sname, name, sizeof(sname));
449     sname[sizeof(sname) - 1] = '\0';
450     total = strlen(sname);
451     if (!strcmp(&sname[total - 9], ".readonly")) {
452         /*discard the last 8 chars */
453         sname[total - 9] = '\0';
454         strcpy(rname, sname);
455         return 0;
456     } else if (!strcmp(&sname[total - 7], ".backup")) {
457         /*discard last 6 chars */
458         sname[total - 7] = '\0';
459         strcpy(rname, sname);
460         return 0;
461     } else {
462         strncpy(rname, name, VOLSER_OLDMAXVOLNAME);
463         rname[VOLSER_OLDMAXVOLNAME] = '\0';
464         return -1;
465     }
466 }
467
468 /* returns 0 if failed */
469 afs_uint32
470 vsu_GetVolumeID(char *astring, struct ubik_client *acstruct, afs_int32 *errp)
471 {
472     char volname[VOLSER_OLDMAXVOLNAME + 1];
473     struct nvldbentry entry;
474     afs_int32 vcode = 0;
475     int total;
476
477     *errp = 0;
478
479     if (isdigit(astring[0])) {
480         char *end;
481         afs_uint32 result;
482         result = strtoul(astring, &end, 10);
483         if (result != UINT_MAX && *end == '\0')
484             return result;
485     }
486
487     /* It was not a volume number but something else */
488     total = strlen(astring);
489     vsu_ExtractName(volname, astring);
490     vcode = VLDB_GetEntryByName(volname, &entry);
491     if (!vcode) {
492       if ((total >= 9) && (!strcmp(&astring[total - 9], ".readonly")))
493         return entry.volumeId[ROVOL];
494       else if ((total >= 7) && (!strcmp(&astring[total - 7], ".backup")))
495         return entry.volumeId[BACKVOL];
496       else
497         return (entry.volumeId[RWVOL]);
498     }
499     *errp = vcode;
500     return 0;           /* can't find volume */
501 }