1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <libintl.h>
33 #include <errno.h>
34 #include <assert.h>
35 #include <sys/types.h>
36 #include <sys/mntent.h>
37 #include <sys/mnttab.h>
38 #include <sys/param.h>
39 #include <libzonecfg.h>
40 #include "zones_strings.h"
41 #include "instzones_lib.h"
42 
43 #define	MNTTAB	"/etc/mnttab"
44 
45 #define	MNTTAB_HUNK	32
46 
47 static struct mnttab *mountTable;
48 static size_t mountTableSize = 0;
49 static boolean_t createdFlag = B_FALSE;
50 
51 /*
52  * Name		: z_createMountTable
53  * Description	: Populate the mountTable Array with mnttab entries
54  * Arguments	: void
55  * Returns	: int
56  *		  0: The Mount Table was succesfully initialized
57  *		 -1: There was an error during initialisation
58  */
59 int
z_createMountTable(void)60 z_createMountTable(void)
61 {
62 	FILE *fp;
63 	struct mnttab ent;
64 	struct mnttab *entp;
65 
66 	if (createdFlag) {
67 		return (0);
68 	}
69 
70 	fp = fopen(MNTTAB, "r");
71 	if (fp == NULL) {
72 		_z_program_error(ERR_OPEN_READ, MNTTAB, errno,
73 		    strerror(errno));
74 		return (-1);
75 	}
76 
77 	/* Put the entries into the table */
78 	mountTable = NULL;
79 	mountTableSize = 0;
80 	createdFlag = B_TRUE;
81 	while (getmntent(fp, &ent) == 0) {
82 		if (mountTableSize % MNTTAB_HUNK == 0) {
83 			mountTable = _z_realloc(mountTable,
84 			    (mountTableSize + MNTTAB_HUNK) * sizeof (ent));
85 		}
86 		entp = &mountTable[mountTableSize++];
87 
88 		/*
89 		 * Zero out any fields we're not using.
90 		 */
91 		(void) memset(entp, 0, sizeof (*entp));
92 
93 		if (ent.mnt_special != NULL)
94 			entp->mnt_special = _z_strdup(ent.mnt_special);
95 		if (ent.mnt_mntopts != NULL)
96 			entp->mnt_mntopts = _z_strdup(ent.mnt_mntopts);
97 		entp->mnt_mountp = _z_strdup(ent.mnt_mountp);
98 		entp->mnt_fstype = _z_strdup(ent.mnt_fstype);
99 	}
100 
101 	(void) fclose(fp);
102 	return (0);
103 }
104 
105 /*
106  * Name		: findPathRWStatus
107  * Description	: Check whether the given path is an mnttab entry
108  * Arguments	: char * - The Path to be verified
109  * Returns	: int
110  *		  -1: The Path is NOT present in the table (mnttab)
111  *		   0: The Path is present in the table and is mounted read-only
112  *		   1: The Path is present in the table and is mounted read-write
113  */
114 static int
findPathRWStatus(const char * a_path)115 findPathRWStatus(const char *a_path)
116 {
117 	int i;
118 
119 	for (i = 0; i < mountTableSize; i++) {
120 		if (strcmp(a_path, mountTable[i].mnt_mountp) == 0) {
121 			if (hasmntopt(&mountTable[i], MNTOPT_RO) != NULL) {
122 				return (0);
123 			} else {
124 				return (1);
125 			}
126 		}
127 	}
128 
129 	return (-1);
130 }
131 
132 
133 /*
134  * Name		: z_isPathWritable
135  * Description	: Check if the given path is in a writable area
136  * Arguments	: char * - The Path to be verified
137  * Returns	: int
138  *		   0: The Path is under a read-only mount
139  *		   1: The Path is under a read-write mount
140  * NOTE		: This funcion automatically initialises
141  *		  the mountPoint table if needed.
142  */
143 int
z_isPathWritable(const char * a_str)144 z_isPathWritable(const char *a_str)
145 {
146 	int i, result, slen;
147 	char a_path[MAXPATHLEN];
148 
149 	if (!createdFlag) {
150 		if (z_createMountTable() != 0) {
151 			return (1);
152 		}
153 	}
154 
155 	(void) strlcpy(a_path, a_str, sizeof (a_path));
156 	slen = strlen(a_path);
157 
158 	/*
159 	 * This for loop traverses Path backwards, incrementally removing the
160 	 * basename of Path and looking for the resultant directory in the
161 	 * mnttab.  Once found, it returns the rw status of that file system.
162 	 */
163 	for (i = slen; i > 0; i--) {
164 		if ((a_path[i] == '/') || (a_path[i] == '\0')) {
165 			a_path[i] = '\0';
166 			result = findPathRWStatus(a_path);
167 			if (result != -1) {
168 				return (result);
169 			}
170 		}
171 	}
172 
173 	return (1);
174 }
175 
176 /*
177  * Name		: z_destroyMountTable
178  * Description	: Clear the entries in the mount table
179  * Arguments	: void
180  * Returns	: void
181  */
182 void
z_destroyMountTable(void)183 z_destroyMountTable(void)
184 {
185 	int i;
186 
187 	if (!createdFlag) {
188 		return;
189 	}
190 
191 	if (mountTable == NULL) {
192 		return;
193 	}
194 
195 	for (i = 0; i < mountTableSize; i++) {
196 		free(mountTable[i].mnt_mountp);
197 		free(mountTable[i].mnt_fstype);
198 		free(mountTable[i].mnt_special);
199 		free(mountTable[i].mnt_mntopts);
200 		assert(mountTable[i].mnt_time == NULL);
201 	}
202 
203 	free(mountTable);
204 	mountTable = NULL;
205 	mountTableSize = 0;
206 	createdFlag = B_FALSE;
207 }
208 
209 /*
210  * Name		: z_resolve_lofs
211  * Description	: Loop over potential loopback mounts and symlinks in a
212  *		  given path and resolve them all down to an absolute path.
213  * Arguments	: char * - path to resolve.  path is in writable storage.
214  *		  size_t - length of path storage.
215  * Returns	: void
216  */
217 void
z_resolve_lofs(char * path,size_t pathlen)218 z_resolve_lofs(char *path, size_t pathlen)
219 {
220 	int len, arlen, i;
221 	const char *altroot;
222 	char tmppath[MAXPATHLEN];
223 	boolean_t outside_altroot;
224 
225 	if ((len = resolvepath(path, tmppath, sizeof (tmppath))) == -1)
226 		return;
227 
228 	tmppath[len] = '\0';
229 	(void) strlcpy(path, tmppath, pathlen);
230 
231 	if (z_createMountTable() == -1)
232 		return;
233 
234 	altroot = zonecfg_get_root();
235 	arlen = strlen(altroot);
236 	outside_altroot = B_FALSE;
237 	for (;;) {
238 		struct mnttab *mnp;
239 
240 		/* Search in reverse order to find longest match */
241 		for (i = mountTableSize; i > 0; i--) {
242 			mnp = &mountTable[i - 1];
243 			if (mnp->mnt_fstype == NULL ||
244 			    mnp->mnt_mountp == NULL ||
245 			    mnp->mnt_special == NULL)
246 				continue;
247 			len = strlen(mnp->mnt_mountp);
248 			if (strncmp(mnp->mnt_mountp, path, len) == 0 &&
249 			    (path[len] == '/' || path[len] == '\0'))
250 				break;
251 		}
252 		if (i <= 0)
253 			break;
254 
255 		/* If it's not a lofs then we're done */
256 		if (strcmp(mnp->mnt_fstype, MNTTYPE_LOFS) != 0)
257 			break;
258 
259 		if (outside_altroot) {
260 			char *cp;
261 			int olen = sizeof (MNTOPT_RO) - 1;
262 
263 			/*
264 			 * If we run into a read-only mount outside of the
265 			 * alternate root environment, then the user doesn't
266 			 * want this path to be made read-write.
267 			 */
268 			if (mnp->mnt_mntopts != NULL &&
269 			    (cp = strstr(mnp->mnt_mntopts, MNTOPT_RO)) !=
270 			    NULL &&
271 			    (cp == mnp->mnt_mntopts || cp[-1] == ',') &&
272 			    (cp[olen] == '\0' || cp[olen] == ',')) {
273 				break;
274 			}
275 		} else if (arlen > 0 &&
276 		    (strncmp(mnp->mnt_special, altroot, arlen) != 0 ||
277 		    (mnp->mnt_special[arlen] != '\0' &&
278 		    mnp->mnt_special[arlen] != '/'))) {
279 			outside_altroot = B_TRUE;
280 		}
281 		/* use temporary buffer because new path might be longer */
282 		(void) snprintf(tmppath, sizeof (tmppath), "%s%s",
283 		    mnp->mnt_special, path + len);
284 		if ((len = resolvepath(tmppath, path, pathlen)) == -1)
285 			break;
286 		path[len] = '\0';
287 	}
288 }
289