xref: /illumos-gate/usr/src/common/zfs/zfs_namecheck.c (revision 20a7641f9918de8574b8b3b47dbe35c4bfc78df1)
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  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 /*
26  * Copyright (c) 2013, 2016 by Delphix. All rights reserved.
27  */
28 
29 /*
30  * Common name validation routines for ZFS.  These routines are shared by the
31  * userland code as well as the ioctl() layer to ensure that we don't
32  * inadvertently expose a hole through direct ioctl()s that never gets tested.
33  * In userland, however, we want significantly more information about _why_ the
34  * name is invalid.  In the kernel, we only care whether it's valid or not.
35  * Each routine therefore takes a 'namecheck_err_t' which describes exactly why
36  * the name failed to validate.
37  */
38 
39 #if defined(_KERNEL)
40 #include <sys/systm.h>
41 #else
42 #include <string.h>
43 #endif
44 
45 #include <sys/dsl_dir.h>
46 #include <sys/param.h>
47 #include <sys/nvpair.h>
48 #include "zfs_namecheck.h"
49 #include "zfs_deleg.h"
50 
51 /*
52  * Deeply nested datasets can overflow the stack, so we put a limit
53  * in the amount of nesting a path can have. zfs_max_dataset_nesting
54  * can be tuned temporarily to fix existing datasets that exceed our
55  * predefined limit.
56  */
57 int zfs_max_dataset_nesting = 50;
58 
59 static int
60 valid_char(char c)
61 {
62 	return ((c >= 'a' && c <= 'z') ||
63 	    (c >= 'A' && c <= 'Z') ||
64 	    (c >= '0' && c <= '9') ||
65 	    c == '-' || c == '_' || c == '.' || c == ':' || c == ' ');
66 }
67 
68 /*
69  * Looks at a path and returns its level of nesting (depth).
70  */
71 int
72 get_dataset_depth(const char *path)
73 {
74 	const char *loc = path;
75 	int nesting = 0;
76 
77 	/*
78 	 * Keep track of nesting until you hit the end of the
79 	 * path or found the snapshot/bookmark seperator.
80 	 */
81 	for (int i = 0; loc[i] != '\0' &&
82 	    loc[i] != '@' &&
83 	    loc[i] != '#'; i++) {
84 		if (loc[i] == '/')
85 			nesting++;
86 	}
87 
88 	return (nesting);
89 }
90 
91 /*
92  * Snapshot names must be made up of alphanumeric characters plus the following
93  * characters:
94  *
95  *	[-_.: ]
96  *
97  * Returns 0 on success, -1 on error.
98  */
99 int
100 zfs_component_namecheck(const char *path, namecheck_err_t *why, char *what)
101 {
102 	const char *loc;
103 
104 	if (strlen(path) >= ZFS_MAX_DATASET_NAME_LEN) {
105 		if (why)
106 			*why = NAME_ERR_TOOLONG;
107 		return (-1);
108 	}
109 
110 	if (path[0] == '\0') {
111 		if (why)
112 			*why = NAME_ERR_EMPTY_COMPONENT;
113 		return (-1);
114 	}
115 
116 	for (loc = path; *loc; loc++) {
117 		if (!valid_char(*loc)) {
118 			if (why) {
119 				*why = NAME_ERR_INVALCHAR;
120 				*what = *loc;
121 			}
122 			return (-1);
123 		}
124 	}
125 	return (0);
126 }
127 
128 
129 /*
130  * Permissions set name must start with the letter '@' followed by the
131  * same character restrictions as snapshot names, except that the name
132  * cannot exceed 64 characters.
133  *
134  * Returns 0 on success, -1 on error.
135  */
136 int
137 permset_namecheck(const char *path, namecheck_err_t *why, char *what)
138 {
139 	if (strlen(path) >= ZFS_PERMSET_MAXLEN) {
140 		if (why)
141 			*why = NAME_ERR_TOOLONG;
142 		return (-1);
143 	}
144 
145 	if (path[0] != '@') {
146 		if (why) {
147 			*why = NAME_ERR_NO_AT;
148 			*what = path[0];
149 		}
150 		return (-1);
151 	}
152 
153 	return (zfs_component_namecheck(&path[1], why, what));
154 }
155 
156 /*
157  * Dataset paths should not be deeper than zfs_max_dataset_nesting
158  * in terms of nesting.
159  *
160  * Returns 0 on success, -1 on error.
161  */
162 int
163 dataset_nestcheck(const char *path)
164 {
165 	return ((get_dataset_depth(path) < zfs_max_dataset_nesting) ? 0 : -1);
166 }
167 
168 /*
169  * Entity names must be of the following form:
170  *
171  *	[component/]*[component][(@|#)component]?
172  *
173  * Where each component is made up of alphanumeric characters plus the following
174  * characters:
175  *
176  *	[-_.:%]
177  *
178  * We allow '%' here as we use that character internally to create unique
179  * names for temporary clones (for online recv).
180  *
181  * Returns 0 on success, -1 on error.
182  */
183 int
184 entity_namecheck(const char *path, namecheck_err_t *why, char *what)
185 {
186 	const char *end;
187 
188 	/*
189 	 * Make sure the name is not too long.
190 	 */
191 	if (strlen(path) >= ZFS_MAX_DATASET_NAME_LEN) {
192 		if (why)
193 			*why = NAME_ERR_TOOLONG;
194 		return (-1);
195 	}
196 
197 	/* Explicitly check for a leading slash.  */
198 	if (path[0] == '/') {
199 		if (why)
200 			*why = NAME_ERR_LEADING_SLASH;
201 		return (-1);
202 	}
203 
204 	if (path[0] == '\0') {
205 		if (why)
206 			*why = NAME_ERR_EMPTY_COMPONENT;
207 		return (-1);
208 	}
209 
210 	const char *start = path;
211 	boolean_t found_delim = B_FALSE;
212 	for (;;) {
213 		/* Find the end of this component */
214 		end = start;
215 		while (*end != '/' && *end != '@' && *end != '#' &&
216 		    *end != '\0')
217 			end++;
218 
219 		if (*end == '\0' && end[-1] == '/') {
220 			/* trailing slashes are not allowed */
221 			if (why)
222 				*why = NAME_ERR_TRAILING_SLASH;
223 			return (-1);
224 		}
225 
226 		/* Validate the contents of this component */
227 		for (const char *loc = start; loc != end; loc++) {
228 			if (!valid_char(*loc) && *loc != '%') {
229 				if (why) {
230 					*why = NAME_ERR_INVALCHAR;
231 					*what = *loc;
232 				}
233 				return (-1);
234 			}
235 		}
236 
237 		/* Snapshot or bookmark delimiter found */
238 		if (*end == '@' || *end == '#') {
239 			/* Multiple delimiters are not allowed */
240 			if (found_delim != 0) {
241 				if (why)
242 					*why = NAME_ERR_MULTIPLE_DELIMITERS;
243 				return (-1);
244 			}
245 
246 			found_delim = B_TRUE;
247 		}
248 
249 		/* Zero-length components are not allowed */
250 		if (start == end) {
251 			if (why)
252 				*why = NAME_ERR_EMPTY_COMPONENT;
253 			return (-1);
254 		}
255 
256 		/* If we've reached the end of the string, we're OK */
257 		if (*end == '\0')
258 			return (0);
259 
260 		/*
261 		 * If there is a '/' in a snapshot or bookmark name
262 		 * then report an error
263 		 */
264 		if (*end == '/' && found_delim != 0) {
265 			if (why)
266 				*why = NAME_ERR_TRAILING_SLASH;
267 			return (-1);
268 		}
269 
270 		/* Update to the next component */
271 		start = end + 1;
272 	}
273 }
274 
275 /*
276  * Dataset is any entity, except bookmark
277  */
278 int
279 dataset_namecheck(const char *path, namecheck_err_t *why, char *what)
280 {
281 	int ret = entity_namecheck(path, why, what);
282 
283 	if (ret == 0 && strchr(path, '#') != NULL) {
284 		if (why != NULL) {
285 			*why = NAME_ERR_INVALCHAR;
286 			*what = '#';
287 		}
288 		return (-1);
289 	}
290 
291 	return (ret);
292 }
293 
294 /*
295  * mountpoint names must be of the following form:
296  *
297  *	/[component][/]*[component][/]
298  *
299  * Returns 0 on success, -1 on error.
300  */
301 int
302 mountpoint_namecheck(const char *path, namecheck_err_t *why)
303 {
304 	const char *start, *end;
305 
306 	/*
307 	 * Make sure none of the mountpoint component names are too long.
308 	 * If a component name is too long then the mkdir of the mountpoint
309 	 * will fail but then the mountpoint property will be set to a value
310 	 * that can never be mounted.  Better to fail before setting the prop.
311 	 * Extra slashes are OK, they will be tossed by the mountpoint mkdir.
312 	 */
313 
314 	if (path == NULL || *path != '/') {
315 		if (why)
316 			*why = NAME_ERR_LEADING_SLASH;
317 		return (-1);
318 	}
319 
320 	/* Skip leading slash  */
321 	start = &path[1];
322 	do {
323 		end = start;
324 		while (*end != '/' && *end != '\0')
325 			end++;
326 
327 		if (end - start >= ZFS_MAX_DATASET_NAME_LEN) {
328 			if (why)
329 				*why = NAME_ERR_TOOLONG;
330 			return (-1);
331 		}
332 		start = end + 1;
333 
334 	} while (*end != '\0');
335 
336 	return (0);
337 }
338 
339 /*
340  * For pool names, we have the same set of valid characters as described in
341  * dataset names, with the additional restriction that the pool name must begin
342  * with a letter.  The pool names 'raidz' and 'mirror' are also reserved names
343  * that cannot be used.
344  *
345  * Returns 0 on success, -1 on error.
346  */
347 int
348 pool_namecheck(const char *pool, namecheck_err_t *why, char *what)
349 {
350 	const char *c;
351 
352 	/*
353 	 * Make sure the name is not too long.
354 	 * If we're creating a pool with version >= SPA_VERSION_DSL_SCRUB (v11)
355 	 * we need to account for additional space needed by the origin ds which
356 	 * will also be snapshotted: "poolname"+"/"+"$ORIGIN"+"@"+"$ORIGIN".
357 	 * Play it safe and enforce this limit even if the pool version is < 11
358 	 * so it can be upgraded without issues.
359 	 */
360 	if (strlen(pool) >= (ZFS_MAX_DATASET_NAME_LEN - 2 -
361 	    strlen(ORIGIN_DIR_NAME) * 2)) {
362 		if (why)
363 			*why = NAME_ERR_TOOLONG;
364 		return (-1);
365 	}
366 
367 	c = pool;
368 	while (*c != '\0') {
369 		if (!valid_char(*c)) {
370 			if (why) {
371 				*why = NAME_ERR_INVALCHAR;
372 				*what = *c;
373 			}
374 			return (-1);
375 		}
376 		c++;
377 	}
378 
379 	if (!(*pool >= 'a' && *pool <= 'z') &&
380 	    !(*pool >= 'A' && *pool <= 'Z')) {
381 		if (why)
382 			*why = NAME_ERR_NOLETTER;
383 		return (-1);
384 	}
385 
386 	if (strcmp(pool, "mirror") == 0 || strcmp(pool, "raidz") == 0) {
387 		if (why)
388 			*why = NAME_ERR_RESERVED;
389 		return (-1);
390 	}
391 
392 	if (pool[0] == 'c' && (pool[1] >= '0' && pool[1] <= '9')) {
393 		if (why)
394 			*why = NAME_ERR_DISKLIKE;
395 		return (-1);
396 	}
397 
398 	return (0);
399 }
400