Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sbin / mount_umap / mount_umap.c
1 /*
2  * Copyright (c) 1992, 1993, 1994
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software donated to Berkeley by
6  * Jan-Simon Pendry.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the University of
19  *      California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36
37 #ifndef lint
38 static const char copyright[] =
39 "@(#) Copyright (c) 1992, 1993, 1994\n\
40         The Regents of the University of California.  All rights reserved.\n";
41 #endif /* not lint */
42
43 #ifndef lint
44 #if 0
45 static char sccsid[] = "@(#)mount_umap.c        8.5 (Berkeley) 4/26/95";
46 #endif
47 static const char rcsid[] =
48   "$FreeBSD: src/sbin/mount_umap/mount_umap.c,v 1.15 1999/10/09 11:54:13 phk Exp $";
49 #endif /* not lint */
50
51 #include <sys/param.h>
52 #include <sys/mount.h>
53 #include <sys/stat.h>
54
55 #include <miscfs/umapfs/umap.h>
56
57 #include <err.h>
58 #include <stdio.h>
59 #include <string.h>
60 #include <sysexits.h>
61 #include <unistd.h>
62
63 #include "mntopts.h"
64
65 #define ROOTUSER 0
66 /*
67  * This define controls whether any user but the superuser can own and
68  * write mapfiles.  If other users can, system security can be gravely
69  * compromised.  If this is not a concern, undefine SECURITY.
70  */
71 #define MAPSECURITY 1
72
73 /*
74  * This routine provides the user interface to mounting a umap layer.
75  * It takes 4 mandatory parameters.  The mandatory arguments are the place
76  * where the next lower level is mounted, the place where the umap layer is to
77  * be mounted, the name of the user mapfile, and the name of the group
78  * mapfile.  The routine checks the ownerships and permissions on the
79  * mapfiles, then opens and reads them.  Then it calls mount(), which
80  * will, in turn, call the umap version of mount.
81  */
82
83 static struct mntopt mopts[] = {
84         MOPT_STDOPTS,
85         { NULL }
86 };
87
88 static void     usage __P((void)) __dead2;
89
90 int
91 main(argc, argv)
92         int argc;
93         char *argv[];
94 {
95         static char not[] = "; not mounted";
96         struct stat statbuf;
97         struct umap_args args;
98         FILE *fp, *gfp;
99         u_long gmapdata[GMAPFILEENTRIES][2], mapdata[MAPFILEENTRIES][2];
100         int ch, count, gnentries, mntflags, nentries;
101         char *gmapfile, *mapfile, buf[20];
102         char source[MAXPATHLEN], target[MAXPATHLEN];
103         struct vfsconf vfc;
104         int error;
105
106         mntflags = 0;
107         mapfile = gmapfile = NULL;
108         while ((ch = getopt(argc, argv, "g:o:u:")) != -1)
109                 switch (ch) {
110                 case 'g':
111                         gmapfile = optarg;
112                         break;
113                 case 'o':
114                         getmntopts(optarg, mopts, &mntflags, 0);
115                         break;
116                 case 'u':
117                         mapfile = optarg;
118                         break;
119                 case '?':
120                 default:
121                         usage();
122                 }
123         argc -= optind;
124         argv += optind;
125
126         if (argc != 2 || mapfile == NULL || gmapfile == NULL)
127                 usage();
128
129         /* resolve both target and source with realpath(3) */
130         (void)checkpath(argv[0], source);
131         (void)checkpath(argv[1], target);
132
133         /* Read in uid mapping data. */
134         if ((fp = fopen(mapfile, "r")) == NULL)
135                 err(EX_NOINPUT, "%s%s", mapfile, not);
136
137 #ifdef MAPSECURITY
138         /*
139          * Check that group and other don't have write permissions on
140          * this mapfile, and that the mapfile belongs to root.
141          */
142         if (fstat(fileno(fp), &statbuf))
143                 err(EX_OSERR, "%s%s", mapfile, not);
144         if (statbuf.st_mode & S_IWGRP || statbuf.st_mode & S_IWOTH) {
145                 strmode(statbuf.st_mode, buf);
146                 err(EX_NOPERM, "%s: improper write permissions (%s)%s",
147                     mapfile, buf, not);
148         }
149         if (statbuf.st_uid != ROOTUSER)
150                 errx(EX_NOPERM, "%s does not belong to root%s", mapfile, not);
151 #endif /* MAPSECURITY */
152
153         if ((fscanf(fp, "%d\n", &nentries)) != 1)
154                 errx(EX_DATAERR, "%s: nentries not found%s", mapfile, not);
155         if (nentries > MAPFILEENTRIES)
156                 errx(EX_DATAERR,
157                     "maximum number of entries is %d%s", MAPFILEENTRIES, not);
158 #if 0
159         (void)printf("reading %d entries\n", nentries);
160 #endif
161         for (count = 0; count < nentries; ++count) {
162                 if ((fscanf(fp, "%lu %lu\n",
163                     &(mapdata[count][0]), &(mapdata[count][1]))) != 2) {
164                         if (ferror(fp))
165                                 err(EX_OSERR, "%s%s", mapfile, not);
166                         if (feof(fp))
167                                 errx(EX_DATAERR, "%s: unexpected end-of-file%s",
168                                     mapfile, not);
169                         errx(EX_DATAERR, "%s: illegal format (line %d)%s",
170                             mapfile, count + 2, not);
171                 }
172 #if 0
173                 /* Fix a security hole. */
174                 if (mapdata[count][1] == 0)
175                         errx(1, "mapping id 0 not permitted (line %d)%s",
176                             count + 2, not);
177 #endif
178         }
179
180         /* Read in gid mapping data. */
181         if ((gfp = fopen(gmapfile, "r")) == NULL)
182                 err(EX_NOINPUT, "%s%s", gmapfile, not);
183
184 #ifdef MAPSECURITY
185         /*
186          * Check that group and other don't have write permissions on
187          * this group mapfile, and that the file belongs to root.
188          */
189         if (fstat(fileno(gfp), &statbuf))
190                 err(EX_OSERR, "%s%s", gmapfile, not);
191         if (statbuf.st_mode & S_IWGRP || statbuf.st_mode & S_IWOTH) {
192                 strmode(statbuf.st_mode, buf);
193                 err(EX_NOPERM, "%s: improper write permissions (%s)%s",
194                     gmapfile, buf, not);
195         }
196         if (statbuf.st_uid != ROOTUSER)
197                 errx(EX_NOPERM, "%s does not belong to root%s", gmapfile, not);
198 #endif /* MAPSECURITY */
199
200         if ((fscanf(gfp, "%d\n", &gnentries)) != 1)
201                 errx(EX_DATAERR, "%s: nentries not found%s", gmapfile, not);
202         if (gnentries > MAPFILEENTRIES)
203                 errx(EX_DATAERR,
204                     "maximum number of entries is %d%s", GMAPFILEENTRIES, not);
205 #if 0
206         (void)printf("reading %d group entries\n", gnentries);
207 #endif
208
209         for (count = 0; count < gnentries; ++count)
210                 if ((fscanf(gfp, "%lu %lu\n",
211                     &(gmapdata[count][0]), &(gmapdata[count][1]))) != 2) {
212                         if (ferror(gfp))
213                                 err(EX_OSERR, "%s%s", gmapfile, not);
214                         if (feof(gfp))
215                                 errx(EX_DATAERR, "%s: unexpected end-of-file%s",
216                                     gmapfile, not);
217                         errx(EX_DATAERR, "%s: illegal format (line %d)%s",
218                             gmapfile, count + 2, not);
219                 }
220
221
222         /* Setup mount call args. */
223         args.target = source;
224         args.nentries = nentries;
225         args.mapdata = mapdata;
226         args.gnentries = gnentries;
227         args.gmapdata = gmapdata;
228
229         error = getvfsbyname("umap", &vfc);
230         if (error && vfsisloadable("umap")) {
231                 if(vfsload("umap"))
232                         err(1, "vfsload(umap)");
233                 endvfsent();
234                 error = getvfsbyname("umap", &vfc);
235         }
236         if (error)
237                 errx(1, "umap filesystem is not available");
238
239         if (mount(vfc.vfc_name, argv[1], mntflags, &args))
240                 err(1, NULL);
241         exit(0);
242 }
243
244 void
245 usage()
246 {
247         (void)fprintf(stderr,
248 "usage: mount_umap [-o options] -u usermap -g groupmap target_fs mount_point\n");
249         exit(EX_USAGE);
250 }