Add interface to select client security objects
[openafs.git] / src / uss / uss_vol.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 /*
11  *      Implementation of the volume operations used by the AFS user
12  *      account facility.
13  */
14
15 /*
16  * --------------------- Required definitions ---------------------
17  */
18 #include <afsconfig.h>
19 #include <afs/param.h>
20
21
22 #include "uss_vol.h"            /*Interface to this module */
23 #include "uss_common.h"         /*Common definitions */
24 #include "uss_procs.h"          /*Defs from procs module */
25 #include "uss_fs.h"             /*CacheManager ops */
26 #include "uss_acl.h"
27 #include <sys/stat.h>
28 #include <pwd.h>
29 #include <netdb.h>
30 #include <errno.h>
31
32 #include <string.h>
33
34 #include <afs/com_err.h>
35 #include <afs/vlserver.h>
36 #include <afs/vldbint.h>
37 #include <afs/auth.h>
38 #include <afs/cellconfig.h>
39 #include <rx/rx_globals.h>
40 #include <afs/volser.h>
41 #include <afs/volser_prototypes.h>
42 #include <afs/volint.h>
43 #include <afs/keys.h>
44 #include <afs/afsutil.h>
45 #include <ubik.h>
46
47 extern int line;
48
49 /*
50  * ---------------------- Private definitions ---------------------
51  */
52 #undef USS_VOL_DB
53 #undef USS_VOL_DB_SHOW_OVERRIDES
54
55
56 /*
57  * --------------------- Exported definitions ---------------------
58  */
59 /*
60  * The Volume Server interface imports the Ubik connection
61  * structure to use, expecting it to be named "cstruct".  This
62  * is why we have two names here.  Thus, the UV_CreateVolume()
63  * will work and we can avoid nasty little core dumps.
64  */
65 struct ubik_client *uconn_vldbP;        /*Ubik connection struct */
66 struct ubik_client *cstruct;    /*Required name for above */
67
68 /*
69  * ------------------------ Private globals -----------------------
70  */
71 static int initDone = 0;        /*Module initialized? */
72 static int NoAuthFlag = 0;      /*Use -noauth? */
73 static struct rx_connection
74  *serverconns[VLDB_MAXSERVERS]; /*Connection(s) to VLDB
75                                  * server(s) */
76
77
78 /*-----------------------------------------------------------------------
79  * static InitThisModule
80  *
81  * Description:
82  *      Set up this module, namely set up all the client state for
83  *      dealing with the Volume Location Server(s), including
84  *      network connections.
85  *
86  * Arguments:
87  *      a_noAuthFlag : Do we need authentication?
88  *      a_confDir    : Configuration directory to use.
89  *      a_cellName   : Cell we want to talk to.
90  *
91  * Returns:
92  *      0 if everything went fine, or
93  *      lower-level error code otherwise.
94  *
95  * Environment:
96  *      This routine will only be called once.
97  *
98  * Side Effects:
99  *      As advertised.
100  *------------------------------------------------------------------------*/
101
102 static afs_int32
103 InitThisModule(int a_noAuthFlag, char *a_confDir, char *a_cellName)
104 {                               /*InitThisModule */
105 #ifdef USS_VOL_DB
106     static char rn[] = "uss_vol:InitThisModule";
107 #endif
108     register afs_int32 code;    /*Return code */
109     struct afsconf_dir *tdir;   /*Ptr to conf dir info */
110     struct afsconf_cell info;   /*Info about chosen cell */
111     afs_int32 scIndex;          /*Chosen security index */
112     afs_int32 secFlags;
113     struct rx_securityClass *sc;        /*Generated security object */
114     afs_int32 i;                /*Loop index */
115
116     /*
117      * Only once, guys, will 'ya?
118      */
119     if (initDone) {
120 #ifdef USS_VOL_DB
121         printf("[%s] Called multiple times!\n", rn);
122 #endif /* USS_VOL_DB */
123         return (0);
124     }
125
126     /*
127      * Set up our Rx environment.
128      */
129 #ifdef USS_VOL_DB
130     printf("[%s] Initializing Rx environment\n", rn);
131 #endif /* USS_VOL_DB */
132     code = rx_Init(0);
133     if (code) {
134         fprintf(stderr, "%s:  Couldn't initialize Rx.\n", uss_whoami);
135         return (code);
136     }
137     rx_SetRxDeadTime(50);
138
139     /*
140      * Find out all about our configuration.
141      */
142 #ifdef USS_VOL_DB
143     printf("[%s] Handling configuration info\n", rn);
144 #endif /* USS_VOL_DB */
145     tdir = afsconf_Open(a_confDir);
146     if (!tdir) {
147         fprintf(stderr, "%s: Couldn't open configuration directory (%s).\n",
148                 uss_whoami, a_confDir);
149         return (-1);
150     }
151     code = afsconf_GetCellInfo(tdir, a_cellName, AFSCONF_VLDBSERVICE, &info);
152     if (code) {
153         printf("%s: Can't find VLDB server(s) for cell %s\n", uss_whoami,
154                a_cellName);
155         exit(1);
156     }
157 #ifdef USS_VOL_DB
158     printf("[%s] Getting tickets if needed\n", rn);
159 #endif /* USS_VOL_DB */
160
161     secFlags = AFSCONF_SECOPTS_FALLBACK_NULL;
162     if (a_noAuthFlag)
163         secFlags |= AFSCONF_SECOPTS_NOAUTH;
164
165     code = afsconf_PickClientSecObj(tdir, secFlags, &info, a_cellName,
166                                     &sc, &scIndex, NULL);
167     if (code) {
168         printf("%s: Can't create client security object\n", uss_whoami);
169         exit(1);
170     }
171     if (scIndex == 0 && !a_noAuthFlag) {
172         fprintf(stderr,
173                 "%s: Couldn't get AFS tokens, running unauthenticated.\n",
174                 uss_whoami);
175     }
176
177     /*
178      * Tell UV module about default authentication.
179      */
180 #ifdef USS_VOL_DB
181     printf("[%s] Setting UV security: obj 0x%x, index %d\n", rn, sc, scIndex);
182 #endif /* USS_VOL_DB */
183     UV_SetSecurity(sc, scIndex);
184     if (info.numServers > VLDB_MAXSERVERS) {
185         fprintf(stderr, "%s: info.numServers=%d (> VLDB_MAXSERVERS=%d)\n",
186                 uss_whoami, info.numServers, VLDB_MAXSERVERS);
187         exit(1);
188     }
189
190     /*
191      * Connect to each VLDB server for the chosen cell.
192      */
193     for (i = 0; i < info.numServers; i++) {
194 #ifdef USS_VOL_DB
195         printf
196             ("[%s] Connecting to VLDB server 0x%x, port %d, service id %d\n",
197              rn, info.hostAddr[i].sin_addr.s_addr, info.hostAddr[i].sin_port,
198              USER_SERVICE_ID);
199 #endif /* USS_VOL_DB */
200         serverconns[i] =
201             rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
202                              info.hostAddr[i].sin_port, USER_SERVICE_ID, sc,
203                              scIndex);
204     }
205
206     /*
207      * Set up to execute Ubik transactions on the VLDB.
208      */
209 #ifdef USS_VOL_DB
210     printf("[%s] Initializing Ubik interface\n", rn);
211 #endif /* USS_VOL_DB */
212     code = ubik_ClientInit(serverconns, &uconn_vldbP);
213     if (code) {
214         fprintf(stderr, "%s: Ubik client init failed.\n", uss_whoami);
215         return (code);
216     }
217 #ifdef USS_VOL_DB
218     printf("[%s] VLDB ubik connection structure at 0x%x\n", rn, uconn_vldbP);
219 #endif /* USS_VOL_DB */
220
221     /*
222      * Place the ubik VLDB connection structure in its advertised
223      * location.
224      */
225     cstruct = uconn_vldbP;
226
227     /*
228      * Success!
229      */
230     initDone = 1;
231     return (0);
232
233 }                               /*InitThisModule */
234
235
236 /*-----------------------------------------------------------------------
237  * static HostIDToHostName
238  *
239  * Description:
240  *      Given a host ID (in network byte order), figure out the
241  *      corresponding host name.
242  *
243  * Arguments:
244  *      a_hostID   : Host ID in network byte order.
245  *      a_hostName : Ptr to host name buffer.
246  *
247  * Returns:
248  *      Nothing.
249  *
250  * Environment:
251  *      This routine simply calls the hostutil_GetNameByINet()
252  *      function exported by the utility library (util.a).
253  *
254  * Side Effects:
255  *      As advertised.
256  *------------------------------------------------------------------------*/
257
258 static void
259 HostIDToHostName(afs_int32 a_hostID, char *a_hostName)
260 {                               /*HostIDToHostName */
261
262     strcpy(a_hostName, hostutil_GetNameByINet(a_hostID));
263
264 }                               /*HostIDToHostName */
265
266
267 /*-----------------------------------------------------------------------
268  * static PartIDToPartName
269  *
270  * Description:
271  *      Given a partition ID (in network byte order), figure out the
272  *      corresponding partition name.
273  *
274  * Arguments:
275  *      a_partID   : Partition ID in network byte order.
276  *      a_partName : Ptr to partition name buffer.
277  *
278  * Returns:
279  *      0 if everything went well, or
280  *      -1 if the given partition ID couldn't be translated.
281  *
282  * Environment:
283  *      Nothing interesting.
284  *
285  * Side Effects:
286  *      As advertised.
287  *------------------------------------------------------------------------*/
288
289 static afs_int32
290 PartIDToPartName(afs_int32 a_partID, char *a_partName)
291 {                               /*PartIDToPartName */
292 #ifdef USS_VOL_DB
293     static char rn[] = "PartIDToPartName";
294 #endif
295 #ifdef USS_VOL_DB
296     printf("[%s] Translating partition id %d to its name\n", rn, a_partID);
297 #endif /* USS_VOL_DB */
298
299     if ((a_partID < 0) || (a_partID > VOLMAXPARTS))
300         return (-1);
301
302     if (a_partID < 26) {
303         strcpy(a_partName, "/vicep");
304         a_partName[6] = a_partID + 'a';
305         a_partName[7] = '\0';
306     } else {
307         strcpy(a_partName, "/vicep");
308         a_partID -= 26;
309         a_partName[6] = 'a' + (a_partID / 26);
310         a_partName[7] = 'a' + (a_partID % 26);
311         a_partName[8] = '\0';
312     }
313
314 #ifdef USS_VOL_DB
315     printf("[%s] Translation for part ID %d is '%s'\n", rn, a_partID,
316            a_partName);
317 #endif /* USS_VOL_DB */
318     return (0);
319
320 }                               /*PartIDToPartName */
321
322
323 /*------------------------------------------------------------------------
324  * EXPORTED uss_Vol_GetServer
325  *
326  * Environment:
327  *      Nothing interesting.
328  *
329  * Side Effects:
330  *      As advertised.
331  *------------------------------------------------------------------------*/
332
333 afs_int32
334 uss_vol_GetServer(char *a_name)
335 {                               /*uss_vol_GetServer */
336
337     register struct hostent *th;
338     afs_int32 addr;
339     afs_int32 b1, b2, b3, b4;
340     register afs_int32 code;
341
342     code = sscanf(a_name, "%d.%d.%d.%d", &b1, &b2, &b3, &b4);
343     if (code == 4) {
344         /*
345          * Parsed as 128.2.9.4, or similar; return it in network
346          * byte order (128 in byte 0).
347          */
348         addr = (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
349         return htonl(addr);
350     }
351
352     th = gethostbyname(a_name);
353     if (!th)
354         return (0);
355     memcpy(&addr, th->h_addr, sizeof(addr));
356     return (addr);
357
358 }                               /*uss_vol_GetServer */
359
360 /* XXX - This function is unused, and could be deleted */
361 #if 0
362 /*------------------------------------------------------------------------
363  * static GetVolumeType
364  *
365  * Description:
366  *      Translate the given char string representing a volume type to the
367  *      numeric representation.
368  *
369  * Arguments:
370  *      a_type : Char string volume type.
371  *
372  * Returns:
373  *      One of ROVOL, RWVOL, BACKVOL, or -1 on failure.
374  *
375  * Environment:
376  *      Nothing interesting.
377  *
378  * Side Effects:
379  *      As advertised.
380  *------------------------------------------------------------------------*/
381
382 static afs_int32
383 GetVolumeType(char *a_type)
384 {                               /*GetVolumeType */
385
386     if (!strcmp(a_type, "ro"))
387         return (ROVOL);
388     else if (!strcmp(a_type, "rw"))
389         return (RWVOL);
390     else if (!strcmp(a_type, "bk"))
391         return (BACKVOL);
392     else
393         return (-1);
394
395 }                               /*GetVolumeType */
396 #endif
397
398 /*------------------------------------------------------------------------
399  * EXPORTED uss_Vol_GetPartitionID
400  *
401  * Environment:
402  *      It is assumed that partition names may begin with ``/vicep''.
403  *
404  * Side Effects:
405  *      As advertised.
406  *------------------------------------------------------------------------*/
407
408 afs_int32
409 uss_vol_GetPartitionID(char *a_name)
410 {                               /*uss_vol_GetPartitionID */
411
412     register char tc;
413     char ascii[3];
414
415     tc = *a_name;
416     if (tc == 0)
417         return (-1);
418
419     /*
420      * Numbers go straight through.
421      */
422     if (tc >= '0' && tc <= '9') {
423         return (atoi(a_name));
424     }
425
426     /*
427      * Otherwise, check for vicepa or /vicepa, or just plain "a"
428      */
429     ascii[2] = 0;
430     if (strlen(a_name) <= 2) {
431         strcpy(ascii, a_name);
432     } else if (!strncmp(a_name, "/vicep", 6)) {
433         strncpy(ascii, a_name + 6, 2);
434     } else if (!strncmp(a_name, "vicep", 5)) {
435         strncpy(ascii, a_name + 5, 2);
436     } else
437         return (-1);
438
439     /*
440      * Now, partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab,
441      * .../vicepzz, and are numbered from 0.  Do the appropriate conversion.
442      */
443     if (ascii[1] == 0) {
444         /*
445          * Single-char name, 0..25
446          */
447         if (ascii[0] < 'a' || ascii[0] > 'z')
448             return (-1);        /* wrongo */
449         return (ascii[0] - 'a');
450     } else {
451         /*
452          * Two-char name, 26 .. <whatever>
453          */
454         if (ascii[0] < 'a' || ascii[0] > 'z')
455             return (-1);
456         if (ascii[1] < 'a' || ascii[1] > 'z')
457             return (-1);
458         return ((ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26);
459     }
460 }                               /*uss_vol_GetPartitionID */
461
462
463 /*-----------------------------------------------------------------------
464  * static CheckDoubleMount
465  *
466  * Description:
467  *      Make sure we're not trying to mount a volume in the same place
468  *      twice.
469  *
470  * Arguments:
471  *      a_mp    : Mountpoint pathname to check.
472  *      a_oldmp : Ptr to buffer into which the old value of the
473  *                mountpoint is placed (if any).
474  *
475  * Returns:
476  *      0                 if the volume was not previously mounted.
477  *      uss_procs_ANCIENT if there was already a mountpoint AND the
478  *                        user was already recorded in the password
479  *                        file.
480  *      uss_procs_YOUNG   if there was a mountpoint for the user taken
481  *                        from the directory pool, yet the user was not
482  *                        yet in the password file.
483  *
484  * Environment:
485  *      Nothing interesting.
486  *
487  * Side Effects:
488  *      May fill in the a_oldmp buffer with the value of the old
489  *      mountpoint.
490  *------------------------------------------------------------------------*/
491
492 static int
493 CheckDoubleMount(char *a_mp, char *a_oldmp)
494 {                               /*CheckDoubleMount */
495
496 #ifdef USS_VOL_DB
497     static char rn[] = "uss_vol:CheckDoubleMount";
498 #endif
499     int start, len, mlen, tlen;
500     int i = 0;
501     struct passwd *pws;
502     struct stat stbuf;
503
504     pws = getpwuid(atoi(uss_Uid));
505     if (pws != NULL) {
506         /*
507          * User exists in the password file, so they've been fully
508          * created and integrated.  Return the ``ancient'' mountpoint.
509          */
510         strcpy(a_oldmp, pws->pw_dir);
511         return (uss_procs_ANCIENT);
512     }
513
514     if (uss_NumGroups) {
515         /*
516          * $AUTO used. Search among the possible directories.
517          */
518         len = strlen(uss_Auto);
519         mlen = strlen(a_mp);
520         while (strncmp(&a_mp[i], uss_Auto, len)) {
521             a_oldmp[i] = a_mp[i];
522             if (++i > (mlen - len)) {
523                 i = -1;
524                 break;
525             }
526         }
527         if ((start = i) != -1) {
528             /*
529              * $AUTO used in mountpoint.
530              */
531             for (i = 0; i < uss_NumGroups; i++) {
532                 /*
533                  * Copy in the base and tail components.
534                  */
535                 tlen = strlen(uss_DirPool[i]);
536                 strncpy(&a_oldmp[start], uss_DirPool[i], tlen);
537                 strcpy(&a_oldmp[start + tlen], &a_mp[start + len]);
538 #ifdef USS_VOL_DB
539                 printf("%s: Checking '%s' for mount point\n", rn, a_oldmp);
540 #endif /* USS_VOL_DB */
541                 if (lstat(a_oldmp, &stbuf) == 0)        /*mp exists */
542                     if (strcmp(a_oldmp, a_mp))
543                         /* and is different */
544                         /*
545                          * The old mount point exists and is different
546                          * from the current one, so return the fact
547                          * that we have a ``young'' mountpoint.
548                          */
549                         return (uss_procs_YOUNG);
550             }                   /*Check each $AUTO directory */
551         }
552     }
553
554     /*$AUTO has been used */
555     /*
556      * No luck finding the old mount point, so we just return that
557      * this is the first time we've seen this volume.
558      */
559     return (0);
560
561 }                               /*CheckDoubleMount */
562
563
564 /*------------------------------------------------------------------------
565  * EXPORTED uss_vol_CreateVol
566  *
567  * Environment:
568  *      Called from the code generated by the uss grammar.
569  *
570  * Side Effects:
571  *      As advertised.
572  *------------------------------------------------------------------------*/
573
574 afs_int32
575 uss_vol_CreateVol(char *a_volname, char *a_server, char *a_partition,
576                   char *a_quota, char *a_mpoint, char *a_owner,
577                   char *a_acl)
578 {                               /*uss_vol_CreateVol */
579 #ifdef USS_VOL_DB
580     static char rn[] = "uss_vol_CreateVol";     /*Routine name */
581 #endif
582     afs_int32 pname;            /*Partition name */
583     afs_uint32 volid;           /*Volume ID */
584     afs_int32 code;             /*return code */
585     afs_int32 saddr;            /*Socket info for server */
586     int VolExistFlag = 0;       /*Does the volume exist? */
587     int mpExistFlag = 0;        /*Does the mountpoint exist? */
588     char *Oldmpoint = NULL;     /*Old mountpoint name, if any */
589     char tmp_str[uss_MAX_SIZE]; /*Useful string buffer */
590     int o;                      /*Owner's user id */
591     char userinput[64];         /*User's input */
592     struct uss_subdir *new_dir; /*Used to remember original ACL */
593
594     /*
595      * Don't do anything if there's already a problem.
596      */
597     if (uss_syntax_err)
598         return (1);
599
600 #ifdef USS_VOL_DB
601     fprintf(stderr, "%s:uss_vol_CreateVol params:\n", rn);
602     fprintf(stderr,
603             "%s: volname '%s', server '%s', partition '%s', quota '%s', mpoint '%s', owner '%s', acl '%s'\n",
604             rn, a_volname, a_server, a_partition, a_quota, a_mpoint, a_owner,
605             a_acl);
606 #endif /* USS_VOL_DB */
607
608     /*
609      * All of the parameters passed in are taken from the template
610      * file.  Override these values if the user has explicitly set
611      * them, namely if the uss commons have non-null strings.
612      */
613     if (uss_Server[0] != '\0') {
614 #ifdef USS_VOL_DB_SHOW_OVERRIDES
615         if (uss_verbose)
616             fprintf(stderr,
617                     "%s: Overriding server field: template value is '%s', overridden to '%s'\n",
618                     rn, a_server, uss_Server);
619 #endif /* USS_VOL_DB_SHOW_OVERRIDES */
620         a_server = uss_Server;
621     }
622
623     if (uss_Partition[0] != '\0') {
624 #ifdef USS_VOL_DB_SHOW_OVERRIDES
625         if (uss_verbose)
626             fprintf(stderr,
627                     "%s: Overriding partition field: template value is '%s', overridden to '%s'\n",
628                     rn, a_partition, uss_Partition);
629 #endif /* USS_VOL_DB_SHOW_OVERRIDES */
630         a_partition = uss_Partition;
631     }
632
633     if (uss_MountPoint[0] != '\0') {
634 #ifdef USS_VOL_DB_SHOW_OVERRIDES
635         if (uss_verbose)
636             fprintf(stderr,
637                     "%s: overriding mountpoint field: template value is '%s', overridden to '%s'\n",
638                     rn, a_mpoint, uss_MountPoint);
639 #endif /* USS_VOL_DB_SHOW_OVERRIDES */
640         a_mpoint = uss_MountPoint;
641     }
642 #ifdef USS_VOL_DB_SHOW_OVERRIDES
643     printf("%s: Params after overrides:\n", uss_whoami);
644     printf
645         ("%s: volname '%s', server '%s', partition '%s', quota '%s', mpoint '%s', owner '%s', acl '%s'\n",
646          uss_whoami, a_volname, a_server, a_partition, a_quota, a_mpoint,
647          a_owner, a_acl);
648 #endif /* USS_VOL_DB_SHOW_OVERRIDES */
649
650     if (uss_verbose)
651         fprintf(stderr,
652                 "Creating volume '%s' on server '%s', partition '%s'\n",
653                 a_volname, a_server, a_partition);
654
655     saddr = uss_vol_GetServer(a_server);
656     if (!saddr) {
657         uss_procs_PrintErr(line,
658                            "File server '%s' not found in config info\n",
659                            a_server);
660         return (1);
661     }
662     pname = uss_vol_GetPartitionID(a_partition);
663     if (pname < 0) {
664         uss_procs_PrintErr(line, "Couldn't interpret partition name '%s'\n",
665                            a_partition);
666         return (1);
667     }
668
669     /*
670      * Make sure our VLDB connection(s) is/are set up before actually
671      * trying to perform a volume creation creation.
672      */
673     if (!initDone) {
674         code = InitThisModule(NoAuthFlag, uss_ConfDir, uss_Cell);
675         if (code) {
676             afs_com_err(uss_whoami, code,
677                     "while inititializing VLDB connection(s)\n");
678             return (code);
679         }
680     }
681     /*Initialize VLDB connection(s) */
682     if (!uss_DryRun) {
683 #ifdef USS_VOL_DB
684         printf("%s: Creating volume on srv 0x%x, part %d, vol name '%s'\n",
685                rn, saddr, pname, a_volname);
686 #endif /* USS_VOL_DB */
687         code = UV_CreateVolume(saddr, pname, a_volname, &volid);
688         if (code) {
689             if (code == VL_NAMEEXIST) {
690                 VolExistFlag = 1;
691                 fprintf(stderr,
692                         "%s: Warning; Volume '%s' exists, using existing one.\n",
693                         uss_whoami, a_volname);
694
695                 /*
696                  * We should get the volid here if we want to use it, but
697                  * we don't need it right now.  What we DO need, though, is
698                  * to ask our caller if it's OK to overwrite the user's files
699                  * if they're pre-existing.
700                  */
701                 if (!uss_OverwriteThisOne) {
702                     printf
703                         ("Overwrite files in pre-existing '%s' volume? [y, n]: ",
704                          a_volname);
705                     scanf("%s", userinput);
706                     if ((userinput[0] == 'y') || (userinput[0] == 'Y')) {
707                         printf("\t[Overwriting allowed]\n");
708                         uss_OverwriteThisOne = 1;
709                     } else
710                         printf("\t[Overwriting not permitted]\n");
711                 }               /*Overwriting not previously allowed */
712             } /*Volume already existed */
713             else {
714                 uss_procs_PrintErr(line,
715                                    "Couldn't create volume '%s' [error %d]: %s\n",
716                                    a_volname, code, strerror(errno));
717                 return (1);
718             }                   /*Failure was NOT because it already existed */
719         }                       /*UV_CreateVolume failed */
720     } /*Not a dry run */
721     else {
722         fprintf(stderr,
723                 "\t[Dry run: Creating volume '%s' on '%s', partition '%s']\n",
724                 a_volname, a_server, a_partition);
725     }                           /*Not a dry run */
726
727     /* OK, we want to make sure we don't double-mount the volume.
728      * If the volume existed, it can be the case that it is
729      * already mounted somewhere else (because of $AUTO or others).
730      * Let's check for that.  Note: we never enter this portion of
731      * the code if we're doing a dry run.
732      */
733     if (VolExistFlag) {
734         if ((Oldmpoint = (char *)malloc(strlen(a_mpoint) + 50)) == NULL) {
735             fprintf(stderr, "%s: No more memory!\n", uss_whoami);
736             return (1);
737         }
738
739         mpExistFlag = CheckDoubleMount(a_mpoint, Oldmpoint);
740         if (mpExistFlag == uss_procs_ANCIENT) {
741             fprintf(stderr,
742                     "%s:\t*** WARNING ***; This user (%s) is already in passwd file (or equivalent). IGNORED.\n",
743                     uss_whoami, uss_User);
744             free(Oldmpoint);
745             uss_syntax_err = 1; /*I know, I know, it's not a SYNTAX error */
746             uss_ignoreFlag = 1;
747             return (0);
748         }
749         if (mpExistFlag == uss_procs_YOUNG) {
750             fprintf(stderr,
751                     "%s: Warning; Volume '%s' is already mounted on %s.  Using the existing one.\n",
752                     uss_whoami, a_volname, Oldmpoint);
753             a_mpoint = Oldmpoint;
754         }
755     }
756
757     if (mpExistFlag == 0) {
758         extern int local_Cell;
759         /*
760          * Let's mount it.
761          */
762         if (local_Cell)
763             sprintf(tmp_str, "#%s.", a_volname);
764         else
765             sprintf(tmp_str, "#%s:%s.", uss_Cell, a_volname);
766         if (!uss_DryRun) {
767             if (symlink(tmp_str, a_mpoint)) {
768                 if (errno == EEXIST) {
769                     fprintf(stderr,
770                             "%s: Warning: Mount point '%s' already exists.\n",
771                             uss_whoami, a_mpoint);
772                 } else {
773                     fprintf(stderr,
774                             "%s: Can't mount volume '%s' on '%s': %s\n",
775                             uss_whoami, a_volname, a_mpoint, strerror(errno));
776                     if (Oldmpoint)
777                         free(Oldmpoint);
778                     return (1);
779                 }               /*There was already something mounted there */
780             }                   /*Mount failed */
781         } /*Dry run */
782         else {
783             fprintf(stderr, "\t[Dry run: Mounting '%s' at '%s']\n", tmp_str,
784                     a_mpoint);
785         }                       /*Not a dry run */
786     }
787
788     /*Mount point didn't already exist */
789     /*
790      * Set the volume disk quota.
791      */
792     if (!uss_DryRun) {
793         if ((code = uss_acl_SetDiskQuota(a_mpoint, atoi(a_quota))))
794             return (code);
795     } /*Dry run */
796     else {
797         fprintf(stderr,
798                 "\t[Dry run: Setting disk quota for '%s' to %s blocks]\n",
799                 a_mpoint, a_quota);
800     }                           /*Not a dry run */
801
802     /*Copy mpoint into $MTPT for others to use */
803     strcpy(uss_MountPoint, a_mpoint);
804
805     o = uss_procs_GetOwner(a_owner);
806     if (!uss_DryRun) {
807         if (chown(a_mpoint, o, -1)) {
808             fprintf(stderr,
809                     "%s: Can't chown() mountpoint '%s' to owner '%s' (uid %d): %s\n",
810                     uss_whoami, a_mpoint, a_owner, o, strerror(errno));
811             if (Oldmpoint)
812                 free(Oldmpoint);
813             return (1);
814         }                       /*chown failed */
815     } /*Dry run */
816     else {
817         fprintf(stderr,
818                 "\t[Dry run: chown() mountpoint '%s' to be owned by user]\n",
819                 a_mpoint);
820     }                           /*Not a dry run */
821
822     /*
823      * Set the ACL on the user's home directory so that, for the duration of
824      * the account creation, only the uss_AccountCreator has any rights on the
825      * files therein.  Make sure to clear this ACL to remove anyone that might
826      * already be there due to volume creation defaults.  We will set this ACL
827      * properly, as well as all ACLs of future subdirectories,as the very last
828      * thing we do to the new account.
829      */
830     new_dir = (struct uss_subdir *)malloc(sizeof(struct uss_subdir));
831     new_dir->previous = uss_currentDir;
832     new_dir->path = (char *)malloc(strlen(a_mpoint) + 1);
833     strcpy(new_dir->path, a_mpoint);
834     new_dir->finalACL = (char *)malloc(strlen(a_acl) + 1);
835     strcpy(new_dir->finalACL, a_acl);
836     uss_currentDir = new_dir;
837     sprintf(tmp_str, "%s %s all", a_mpoint, uss_AccountCreator);
838
839     if (Oldmpoint)
840         free(Oldmpoint);
841
842     if (!uss_DryRun) {
843         if (uss_verbose)
844             fprintf(stderr, "Setting ACL: '%s'\n", tmp_str);
845         if (uss_acl_SetAccess(tmp_str, 1, 0))
846             return (1);
847     } /*For real */
848     else {
849         fprintf(stderr, "\t[Dry run: uss_acl_SetAccess(%s)]\n", tmp_str);
850     }
851     return (0);
852 }                               /*uss_vol_CreateVol */
853
854
855 /*------------------------------------------------------------------------
856  * EXPORTED uss_vol_DeleteVol
857  *
858  * Environment:
859  *      Nothing interesting.
860  *
861  * Side Effects:
862  *      As advertised.
863  *------------------------------------------------------------------------*/
864
865 afs_int32
866 uss_vol_DeleteVol(char *a_volName, afs_int32 a_volID, char *a_servName,
867                   afs_int32 a_servID, char *a_partName, afs_int32  a_partID)
868 {                               /*uss_vol_DeleteVol */
869
870 #ifdef USS_VOL_DB
871     static char rn[] = "uss_vol_DeleteVol";     /*Routine name */
872 #endif
873     register afs_int32 code = 0;        /*Return code */
874
875     /*
876      * Make sure we've initialized our VLDB connection(s) before
877      * proceeding apace.
878      */
879     if (!initDone) {
880         code = InitThisModule(NoAuthFlag, uss_ConfDir, uss_Cell);
881         if (code)
882             return (code);
883     }
884
885     if (!uss_DryRun) {
886         /*
887          * Go for the deletion.
888          */
889 #ifdef USS_VOL_DB
890         printf
891             ("%s: Deleting volume '%s' (ID %d) on FileServer '%s' (0x%x), partition '%s' (%d)\n",
892              rn, a_volName, a_volID, a_servName, a_servID, a_partName,
893              a_partID);
894 #endif /* USS_VOL_DB */
895
896         code = UV_DeleteVolume(a_servID, a_partID, a_volID);
897         if (code)
898             printf("%s: Can't delete volume '%s'\n", uss_whoami, a_volName);
899     } else
900         printf("\t[Dry run - volume '%s' NOT removed]\n", a_volName);
901
902     return (code);
903
904 }                               /*uss_vol_DeleteVol */
905
906
907 /*------------------------------------------------------------------------
908  * static GetServerAndPart
909  *
910  * Description:
911  *      Given a VLDB entry, return the server and partition IDs for
912  *      the read/write volume.
913  *
914  * Arguments:
915  *      a_vldbEntryP : Ptr to VLDB entry.
916  *      a_servIDP    : Ptr to server ID to set.
917  *      a_partIDP    : Ptr to partition ID to set.
918  *
919  * Returns:
920  *      0 if everything went well, or
921  *      -1 otherwise.
922  *
923  * Environment:
924  *      Nothing interesting.
925  *
926  * Side Effects:
927  *      As advertised.
928  *------------------------------------------------------------------------*/
929
930 static afs_int32
931 GetServerAndPart(struct nvldbentry *a_vldbEntryP, afs_int32 *a_servIDP,
932                  afs_int32 *a_partIDP)
933 {                               /*GetServerAndPart */
934
935     /*
936      * It really looks like all we need to do is pull off the
937      * first entry's info.
938      */
939     *a_servIDP = a_vldbEntryP->serverNumber[0];
940     *a_partIDP = a_vldbEntryP->serverPartition[0];
941     return (0);
942
943 }                               /*GetServerAndPart */
944
945
946 /*------------------------------------------------------------------------
947  * static ovlentry_to_nvlentry
948  *
949  * Description:
950  *      Converts a vldbentry to nvldbentry.
951  *
952  * Arguments:
953  *      oentryp   IN  : Ptr to vldbentry.
954  *      nentryp   OUT : Ptr to nvldbentry.
955  *
956  * Returns:
957  *      None
958  *
959  * Environment:
960  *      Nothing interesting.
961  *
962  * Side Effects:
963  *      None.
964  *------------------------------------------------------------------------*/
965
966 static void
967 ovlentry_to_nvlentry(struct vldbentry *oentryp,
968                      struct nvldbentry *nentryp)
969 {
970     register int i;
971
972     memset(nentryp, 0, sizeof(struct nvldbentry));
973     strncpy(nentryp->name, oentryp->name, sizeof(nentryp->name));
974     for (i = 0; i < oentryp->nServers; i++) {
975         nentryp->serverNumber[i] = oentryp->serverNumber[i];
976         nentryp->serverPartition[i] = oentryp->serverPartition[i];
977         nentryp->serverFlags[i] = oentryp->serverFlags[i];
978     }
979     nentryp->nServers = oentryp->nServers;
980     for (i = 0; i < MAXTYPES; i++)
981         nentryp->volumeId[i] = oentryp->volumeId[i];
982     nentryp->cloneId = oentryp->cloneId;
983     nentryp->flags = oentryp->flags;
984 }
985
986
987 /*------------------------------------------------------------------------
988  * static uss_vol_GetEntryByID
989  *
990  * Description:
991  *      Obtains a nvldbentry whether new or old forms of
992  *      ubik_VL_GetEntryByID are required.
993  *
994  * Arguments:
995  *      cstruct      : Ptr to ubik_client.
996  *      volid        : Volume ID for which entry is being obtained.
997  *      voltype      : Required volume type
998  *      entryp       : Ptr to nvldbentry to receive the output on success.
999  *
1000  * Returns:
1001  *      0 if everything went well, or
1002  *      ubik return code otherwise.
1003  *
1004  * Environment:
1005  *      Nothing interesting.
1006  *
1007  * Side Effects:
1008  *      None.
1009  *------------------------------------------------------------------------*/
1010
1011 static int
1012 uss_vol_GetEntryByID(struct ubik_client *cstruct, afs_uint32 volid,
1013                      afs_int32 voltype, struct nvldbentry *entryp)
1014 {
1015     struct vldbentry oentry;
1016     int code;
1017
1018     code = ubik_VL_GetEntryByIDN(cstruct, 0, volid, voltype, entryp);
1019     if (code == RXGEN_OPCODE) {
1020         code =
1021             ubik_VL_GetEntryByID(cstruct, 0, volid, voltype, &oentry);
1022         if (!code)
1023             ovlentry_to_nvlentry(&oentry, entryp);
1024     }
1025     return code;
1026 }
1027
1028
1029 /*------------------------------------------------------------------------
1030  * EXPORTED uss_vol_GetVolInfoFromMountPoint
1031  *
1032  * Environment:
1033  *      If the mountpoint path provided is not
1034  *
1035  * Side Effects:
1036  *      As advertised.
1037  *------------------------------------------------------------------------*/
1038
1039 afs_int32
1040 uss_vol_GetVolInfoFromMountPoint(char *a_mountpoint)
1041 {                               /*uss_vol_GetVolInfoFromMountPoint */
1042 #ifdef USS_VOL_DB
1043     static char rn[] = "uss_vol_GetVolInfoFromMountPoint";
1044 #endif
1045     register afs_int32 code;    /*Return code */
1046     uss_VolumeStatus_t *statusP;        /*Ptr to returned status */
1047     afs_int32 volID;            /*Volume ID */
1048     struct nvldbentry vldbEntry;        /*VLDB entry for volume */
1049     afs_int32 serverID;         /*Addr of host FileServer */
1050     afs_int32 partID;           /*Volume's partition ID */
1051
1052     /*
1053      * Set up to ask the CacheManager to give us all the info
1054      * it has about the given mountpoint.
1055      */
1056     code = uss_fs_GetVolStat(a_mountpoint, uss_fs_OutBuff, USS_FS_MAX_SIZE);
1057 #ifdef USS_VOL_DB
1058     printf("[%s] Result of uss_fs_GetVolStat: code = %d, errno = %d\n", rn,
1059            code, errno);
1060 #endif /* USS_VOL_DB */
1061     if (code) {
1062         if (errno == EINVAL || errno == ENOENT || errno == ENODEV) {
1063             /*
1064              * We were given a mountpoint pathname that doesn't
1065              * point to a volume, or a mountpoint that has already
1066              * been deleted.  This means that there is no info
1067              * to get from this pathname.  Zero out the volume,
1068              * server & partition info and return successfully.
1069              */
1070             uss_Volume[0] = '\0';
1071             uss_Server[0] = '\0';
1072             uss_Partition[0] = '\0';
1073             uss_VolumeID = 0;
1074             uss_ServerID = 0;
1075             uss_PartitionID = 0;
1076             if (uss_verbose) {
1077                 printf("%s: Warning: Mountpoint pathname '%s': ", uss_whoami,
1078                        a_mountpoint);
1079                 if (errno == EINVAL)
1080                     printf("Volume not reachable\n");
1081                 else if (errno == ENODEV)
1082                     printf("No such device\n");
1083                 else
1084                     printf("Not found\n");
1085             }
1086             return (0);
1087         } else {
1088             printf("%s: Can't get volume information from mountpoint '%s'\n",
1089                    uss_whoami, a_mountpoint);
1090             return (code);
1091         }
1092     }
1093
1094     /*Can't get volume status */
1095     /*
1096      * Pull out the volume name from the returned information and store
1097      * it in the common area.  It resides right after the basic volume
1098      * status structure.
1099      */
1100     statusP = (uss_VolumeStatus_t *) uss_fs_OutBuff;
1101     strcpy(uss_Volume, (((char *)statusP) + sizeof(*statusP)));
1102     volID = statusP->Vid;
1103     uss_VolumeID = volID;
1104     if (volID == 0) {
1105         printf("%s: Illegal volume ID: %d\n", uss_whoami, volID);
1106         return (-1);
1107     }
1108
1109     /*
1110      * With the volume name in hand, find out where that volume
1111      * lives.  Make sure our VLDB stuff has been initialized first.
1112      */
1113     if (!initDone) {
1114         code = InitThisModule(NoAuthFlag, uss_ConfDir, uss_Cell);
1115         if (code)
1116             return (code);
1117     }
1118     code = uss_vol_GetEntryByID( uconn_vldbP, volID, -1, &vldbEntry);
1119     if (code) {
1120         printf("%s: Can't fetch VLDB entry for volume ID %d\n", uss_whoami,
1121                volID);
1122         return (code);
1123     }
1124
1125     /*
1126      * Translate the given VLDB entry from network to host format, then
1127      * checking on the volume's validity.  Specifically, it must be a
1128      * read/write volume and must only exist on one server.
1129      */
1130     MapHostToNetwork(&vldbEntry);
1131     if (vldbEntry.volumeId[RWVOL] != volID) {
1132         printf("%s: Volume '%s' (ID %d) is not a read/write volume!!\n",
1133                uss_whoami, uss_Volume, volID);
1134         return (-1);
1135     }
1136     if (vldbEntry.nServers != 1) {
1137         printf("%s: Volume '%s' (ID %d) exists on multiple servers!!\n",
1138                uss_whoami, uss_Volume, volID);
1139         return (-1);
1140     }
1141
1142     /*
1143      * Pull out the int32words containing the server and partition info
1144      * for the read/write volume.
1145      */
1146     code = GetServerAndPart(&vldbEntry, &serverID, &partID);
1147     if (code) {
1148         printf
1149             ("%s: Can't get server/partition info from VLDB entry for volume '%s' (ID %d)\n",
1150              uss_whoami, uss_Volume, volID);
1151         return (-1);
1152     }
1153
1154     /*
1155      * Store the raw data, then translate the FileServer address to a
1156      * host name, and the partition ID to a partition name.
1157      */
1158     uss_ServerID = serverID;
1159     uss_PartitionID = partID;
1160     HostIDToHostName(serverID, uss_Server);
1161 #ifdef USS_VOL_DB
1162     printf("[%s] Server ID 0x%x translated to '%s'\n", rn, serverID,
1163            uss_Server);
1164 #endif /* USS_VOL_DB */
1165     code = PartIDToPartName(partID, uss_Partition);
1166     if (code) {
1167         printf("%s: Error translating partition ID %d to partition name\n",
1168                uss_whoami, partID);
1169         return (code);
1170     }
1171
1172     /*
1173      * We got it, home boy.
1174      */
1175     return (0);
1176
1177 }                               /*uss_vol_GetVolInfoFromMountPoint */