1fa9e4066Sahrens /*
2fa9e4066Sahrens  * CDDL HEADER START
3fa9e4066Sahrens  *
4fa9e4066Sahrens  * The contents of this file are subject to the terms of the
51d452cf5Sahrens  * Common Development and Distribution License (the "License").
61d452cf5Sahrens  * You may not use this file except in compliance with the License.
7fa9e4066Sahrens  *
8fa9e4066Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fa9e4066Sahrens  * or http://www.opensolaris.org/os/licensing.
10fa9e4066Sahrens  * See the License for the specific language governing permissions
11fa9e4066Sahrens  * and limitations under the License.
12fa9e4066Sahrens  *
13fa9e4066Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14fa9e4066Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fa9e4066Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16fa9e4066Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17fa9e4066Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18fa9e4066Sahrens  *
19fa9e4066Sahrens  * CDDL HEADER END
20fa9e4066Sahrens  */
21fa9e4066Sahrens /*
2214843421SMatthew Ahrens  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23fa9e4066Sahrens  * Use is subject to license terms.
24fa9e4066Sahrens  */
2578f17100SMatthew Ahrens /*
26*5ac95da7SSerapheim Dimitropoulos  * Copyright (c) 2013, 2016 by Delphix. All rights reserved.
2778f17100SMatthew Ahrens  */
28fa9e4066Sahrens 
29fa9e4066Sahrens /*
30fa9e4066Sahrens  * Common name validation routines for ZFS.  These routines are shared by the
31fa9e4066Sahrens  * userland code as well as the ioctl() layer to ensure that we don't
32fa9e4066Sahrens  * inadvertently expose a hole through direct ioctl()s that never gets tested.
33fa9e4066Sahrens  * In userland, however, we want significantly more information about _why_ the
34fa9e4066Sahrens  * name is invalid.  In the kernel, we only care whether it's valid or not.
35fa9e4066Sahrens  * Each routine therefore takes a 'namecheck_err_t' which describes exactly why
36fa9e4066Sahrens  * the name failed to validate.
37fa9e4066Sahrens  */
38fa9e4066Sahrens 
39fa9e4066Sahrens #if defined(_KERNEL)
40fa9e4066Sahrens #include <sys/systm.h>
41fa9e4066Sahrens #else
42fa9e4066Sahrens #include <string.h>
43fa9e4066Sahrens #endif
44fa9e4066Sahrens 
45f37ae9a7Sloli #include <sys/dsl_dir.h>
46b81d61a6Slling #include <sys/param.h>
47ecd6cf80Smarks #include <sys/nvpair.h>
48fa9e4066Sahrens #include "zfs_namecheck.h"
49ecd6cf80Smarks #include "zfs_deleg.h"
50fa9e4066Sahrens 
51*5ac95da7SSerapheim Dimitropoulos /*
52*5ac95da7SSerapheim Dimitropoulos  * Deeply nested datasets can overflow the stack, so we put a limit
53*5ac95da7SSerapheim Dimitropoulos  * in the amount of nesting a path can have. zfs_max_dataset_nesting
54*5ac95da7SSerapheim Dimitropoulos  * can be tuned temporarily to fix existing datasets that exceed our
55*5ac95da7SSerapheim Dimitropoulos  * predefined limit.
56*5ac95da7SSerapheim Dimitropoulos  */
57*5ac95da7SSerapheim Dimitropoulos int zfs_max_dataset_nesting = 50;
58*5ac95da7SSerapheim Dimitropoulos 
59fa9e4066Sahrens static int
valid_char(char c)60fa9e4066Sahrens valid_char(char c)
61fa9e4066Sahrens {
62fa9e4066Sahrens 	return ((c >= 'a' && c <= 'z') ||
63fa9e4066Sahrens 	    (c >= 'A' && c <= 'Z') ||
64fa9e4066Sahrens 	    (c >= '0' && c <= '9') ||
656d1e0b89Smarks 	    c == '-' || c == '_' || c == '.' || c == ':' || c == ' ');
66fa9e4066Sahrens }
67fa9e4066Sahrens 
68*5ac95da7SSerapheim Dimitropoulos /*
69*5ac95da7SSerapheim Dimitropoulos  * Looks at a path and returns its level of nesting (depth).
70*5ac95da7SSerapheim Dimitropoulos  */
71*5ac95da7SSerapheim Dimitropoulos int
get_dataset_depth(const char * path)72*5ac95da7SSerapheim Dimitropoulos get_dataset_depth(const char *path)
73*5ac95da7SSerapheim Dimitropoulos {
74*5ac95da7SSerapheim Dimitropoulos 	const char *loc = path;
75*5ac95da7SSerapheim Dimitropoulos 	int nesting = 0;
76*5ac95da7SSerapheim Dimitropoulos 
77*5ac95da7SSerapheim Dimitropoulos 	/*
78*5ac95da7SSerapheim Dimitropoulos 	 * Keep track of nesting until you hit the end of the
79*5ac95da7SSerapheim Dimitropoulos 	 * path or found the snapshot/bookmark seperator.
80*5ac95da7SSerapheim Dimitropoulos 	 */
81*5ac95da7SSerapheim Dimitropoulos 	for (int i = 0; loc[i] != '\0' &&
82*5ac95da7SSerapheim Dimitropoulos 	    loc[i] != '@' &&
83*5ac95da7SSerapheim Dimitropoulos 	    loc[i] != '#'; i++) {
84*5ac95da7SSerapheim Dimitropoulos 		if (loc[i] == '/')
85*5ac95da7SSerapheim Dimitropoulos 			nesting++;
86*5ac95da7SSerapheim Dimitropoulos 	}
87*5ac95da7SSerapheim Dimitropoulos 
88*5ac95da7SSerapheim Dimitropoulos 	return (nesting);
89*5ac95da7SSerapheim Dimitropoulos }
90*5ac95da7SSerapheim Dimitropoulos 
911d452cf5Sahrens /*
921d452cf5Sahrens  * Snapshot names must be made up of alphanumeric characters plus the following
931d452cf5Sahrens  * characters:
941d452cf5Sahrens  *
95*5ac95da7SSerapheim Dimitropoulos  *	[-_.: ]
96*5ac95da7SSerapheim Dimitropoulos  *
97*5ac95da7SSerapheim Dimitropoulos  * Returns 0 on success, -1 on error.
981d452cf5Sahrens  */
991d452cf5Sahrens int
zfs_component_namecheck(const char * path,namecheck_err_t * why,char * what)10078f17100SMatthew Ahrens zfs_component_namecheck(const char *path, namecheck_err_t *why, char *what)
1011d452cf5Sahrens {
1021d452cf5Sahrens 	const char *loc;
1031d452cf5Sahrens 
1049adfa60dSMatthew Ahrens 	if (strlen(path) >= ZFS_MAX_DATASET_NAME_LEN) {
1051d452cf5Sahrens 		if (why)
1061d452cf5Sahrens 			*why = NAME_ERR_TOOLONG;
1071d452cf5Sahrens 		return (-1);
1081d452cf5Sahrens 	}
1091d452cf5Sahrens 
1101d452cf5Sahrens 	if (path[0] == '\0') {
1111d452cf5Sahrens 		if (why)
1121d452cf5Sahrens 			*why = NAME_ERR_EMPTY_COMPONENT;
1131d452cf5Sahrens 		return (-1);
1141d452cf5Sahrens 	}
1151d452cf5Sahrens 
1161d452cf5Sahrens 	for (loc = path; *loc; loc++) {
1171d452cf5Sahrens 		if (!valid_char(*loc)) {
1181d452cf5Sahrens 			if (why) {
1191d452cf5Sahrens 				*why = NAME_ERR_INVALCHAR;
1201d452cf5Sahrens 				*what = *loc;
1211d452cf5Sahrens 			}
1221d452cf5Sahrens 			return (-1);
1231d452cf5Sahrens 		}
1241d452cf5Sahrens 	}
1251d452cf5Sahrens 	return (0);
1261d452cf5Sahrens }
1271d452cf5Sahrens 
128ecd6cf80Smarks 
129ecd6cf80Smarks /*
130ecd6cf80Smarks  * Permissions set name must start with the letter '@' followed by the
131ecd6cf80Smarks  * same character restrictions as snapshot names, except that the name
132ecd6cf80Smarks  * cannot exceed 64 characters.
133*5ac95da7SSerapheim Dimitropoulos  *
134*5ac95da7SSerapheim Dimitropoulos  * Returns 0 on success, -1 on error.
135ecd6cf80Smarks  */
136ecd6cf80Smarks int
permset_namecheck(const char * path,namecheck_err_t * why,char * what)137ecd6cf80Smarks permset_namecheck(const char *path, namecheck_err_t *why, char *what)
138ecd6cf80Smarks {
139ecd6cf80Smarks 	if (strlen(path) >= ZFS_PERMSET_MAXLEN) {
140ecd6cf80Smarks 		if (why)
141ecd6cf80Smarks 			*why = NAME_ERR_TOOLONG;
142ecd6cf80Smarks 		return (-1);
143ecd6cf80Smarks 	}
144ecd6cf80Smarks 
145ecd6cf80Smarks 	if (path[0] != '@') {
146ecd6cf80Smarks 		if (why) {
147ecd6cf80Smarks 			*why = NAME_ERR_NO_AT;
148ecd6cf80Smarks 			*what = path[0];
149ecd6cf80Smarks 		}
150ecd6cf80Smarks 		return (-1);
151ecd6cf80Smarks 	}
152ecd6cf80Smarks 
15378f17100SMatthew Ahrens 	return (zfs_component_namecheck(&path[1], why, what));
154ecd6cf80Smarks }
155ecd6cf80Smarks 
156*5ac95da7SSerapheim Dimitropoulos /*
157*5ac95da7SSerapheim Dimitropoulos  * Dataset paths should not be deeper than zfs_max_dataset_nesting
158*5ac95da7SSerapheim Dimitropoulos  * in terms of nesting.
159*5ac95da7SSerapheim Dimitropoulos  *
160*5ac95da7SSerapheim Dimitropoulos  * Returns 0 on success, -1 on error.
161*5ac95da7SSerapheim Dimitropoulos  */
162*5ac95da7SSerapheim Dimitropoulos int
dataset_nestcheck(const char * path)163*5ac95da7SSerapheim Dimitropoulos dataset_nestcheck(const char *path)
164*5ac95da7SSerapheim Dimitropoulos {
165*5ac95da7SSerapheim Dimitropoulos 	return ((get_dataset_depth(path) < zfs_max_dataset_nesting) ? 0 : -1);
166*5ac95da7SSerapheim Dimitropoulos }
167*5ac95da7SSerapheim Dimitropoulos 
168fa9e4066Sahrens /*
169edb901aaSMarcel Telka  * Entity names must be of the following form:
170fa9e4066Sahrens  *
171*5ac95da7SSerapheim Dimitropoulos  *	[component/]*[component][(@|#)component]?
172fa9e4066Sahrens  *
173fa9e4066Sahrens  * Where each component is made up of alphanumeric characters plus the following
174fa9e4066Sahrens  * characters:
175fa9e4066Sahrens  *
176*5ac95da7SSerapheim Dimitropoulos  *	[-_.:%]
177f0ed2251Sek  *
178f0ed2251Sek  * We allow '%' here as we use that character internally to create unique
179f0ed2251Sek  * names for temporary clones (for online recv).
180*5ac95da7SSerapheim Dimitropoulos  *
181*5ac95da7SSerapheim Dimitropoulos  * Returns 0 on success, -1 on error.
182fa9e4066Sahrens  */
183fa9e4066Sahrens int
entity_namecheck(const char * path,namecheck_err_t * why,char * what)184edb901aaSMarcel Telka entity_namecheck(const char *path, namecheck_err_t *why, char *what)
185fa9e4066Sahrens {
186*5ac95da7SSerapheim Dimitropoulos 	const char *end;
187fa9e4066Sahrens 
188b81d61a6Slling 	/*
189b81d61a6Slling 	 * Make sure the name is not too long.
190b81d61a6Slling 	 */
1919adfa60dSMatthew Ahrens 	if (strlen(path) >= ZFS_MAX_DATASET_NAME_LEN) {
192b81d61a6Slling 		if (why)
193b81d61a6Slling 			*why = NAME_ERR_TOOLONG;
194b81d61a6Slling 		return (-1);
195b81d61a6Slling 	}
196b81d61a6Slling 
197fa9e4066Sahrens 	/* Explicitly check for a leading slash.  */
198fa9e4066Sahrens 	if (path[0] == '/') {
199fa9e4066Sahrens 		if (why)
200fa9e4066Sahrens 			*why = NAME_ERR_LEADING_SLASH;
201fa9e4066Sahrens 		return (-1);
202fa9e4066Sahrens 	}
203fa9e4066Sahrens 
204fa9e4066Sahrens 	if (path[0] == '\0') {
205fa9e4066Sahrens 		if (why)
206fa9e4066Sahrens 			*why = NAME_ERR_EMPTY_COMPONENT;
207fa9e4066Sahrens 		return (-1);
208fa9e4066Sahrens 	}
209fa9e4066Sahrens 
210*5ac95da7SSerapheim Dimitropoulos 	const char *start = path;
211*5ac95da7SSerapheim Dimitropoulos 	boolean_t found_delim = B_FALSE;
212fa9e4066Sahrens 	for (;;) {
213fa9e4066Sahrens 		/* Find the end of this component */
214edb901aaSMarcel Telka 		end = start;
215edb901aaSMarcel Telka 		while (*end != '/' && *end != '@' && *end != '#' &&
216edb901aaSMarcel Telka 		    *end != '\0')
217fa9e4066Sahrens 			end++;
218fa9e4066Sahrens 
219fa9e4066Sahrens 		if (*end == '\0' && end[-1] == '/') {
220fa9e4066Sahrens 			/* trailing slashes are not allowed */
221fa9e4066Sahrens 			if (why)
222fa9e4066Sahrens 				*why = NAME_ERR_TRAILING_SLASH;
223fa9e4066Sahrens 			return (-1);
224fa9e4066Sahrens 		}
225fa9e4066Sahrens 
226fa9e4066Sahrens 		/* Validate the contents of this component */
227edb901aaSMarcel Telka 		for (const char *loc = start; loc != end; loc++) {
228f0ed2251Sek 			if (!valid_char(*loc) && *loc != '%') {
229fa9e4066Sahrens 				if (why) {
230fa9e4066Sahrens 					*why = NAME_ERR_INVALCHAR;
231fa9e4066Sahrens 					*what = *loc;
232fa9e4066Sahrens 				}
233fa9e4066Sahrens 				return (-1);
234fa9e4066Sahrens 			}
235fa9e4066Sahrens 		}
236fa9e4066Sahrens 
237edb901aaSMarcel Telka 		/* Snapshot or bookmark delimiter found */
238edb901aaSMarcel Telka 		if (*end == '@' || *end == '#') {
239edb901aaSMarcel Telka 			/* Multiple delimiters are not allowed */
240edb901aaSMarcel Telka 			if (found_delim != 0) {
241fa9e4066Sahrens 				if (why)
242edb901aaSMarcel Telka 					*why = NAME_ERR_MULTIPLE_DELIMITERS;
243fa9e4066Sahrens 				return (-1);
244fa9e4066Sahrens 			}
245fa9e4066Sahrens 
246*5ac95da7SSerapheim Dimitropoulos 			found_delim = B_TRUE;
247edb901aaSMarcel Telka 		}
248edb901aaSMarcel Telka 
249edb901aaSMarcel Telka 		/* Zero-length components are not allowed */
250edb901aaSMarcel Telka 		if (start == end) {
251edb901aaSMarcel Telka 			if (why)
252edb901aaSMarcel Telka 				*why = NAME_ERR_EMPTY_COMPONENT;
253edb901aaSMarcel Telka 			return (-1);
254fa9e4066Sahrens 		}
255fa9e4066Sahrens 
256edb901aaSMarcel Telka 		/* If we've reached the end of the string, we're OK */
257edb901aaSMarcel Telka 		if (*end == '\0')
258edb901aaSMarcel Telka 			return (0);
259edb901aaSMarcel Telka 
26098579b20Snd 		/*
261edb901aaSMarcel Telka 		 * If there is a '/' in a snapshot or bookmark name
26298579b20Snd 		 * then report an error
26398579b20Snd 		 */
264edb901aaSMarcel Telka 		if (*end == '/' && found_delim != 0) {
26598579b20Snd 			if (why)
26698579b20Snd 				*why = NAME_ERR_TRAILING_SLASH;
26798579b20Snd 			return (-1);
26898579b20Snd 		}
26998579b20Snd 
270fa9e4066Sahrens 		/* Update to the next component */
271edb901aaSMarcel Telka 		start = end + 1;
272fa9e4066Sahrens 	}
273fa9e4066Sahrens }
274fa9e4066Sahrens 
275edb901aaSMarcel Telka /*
276edb901aaSMarcel Telka  * Dataset is any entity, except bookmark
277edb901aaSMarcel Telka  */
278edb901aaSMarcel Telka int
dataset_namecheck(const char * path,namecheck_err_t * why,char * what)279edb901aaSMarcel Telka dataset_namecheck(const char *path, namecheck_err_t *why, char *what)
280edb901aaSMarcel Telka {
281edb901aaSMarcel Telka 	int ret = entity_namecheck(path, why, what);
282edb901aaSMarcel Telka 
283edb901aaSMarcel Telka 	if (ret == 0 && strchr(path, '#') != NULL) {
284edb901aaSMarcel Telka 		if (why != NULL) {
285edb901aaSMarcel Telka 			*why = NAME_ERR_INVALCHAR;
286edb901aaSMarcel Telka 			*what = '#';
287edb901aaSMarcel Telka 		}
288edb901aaSMarcel Telka 		return (-1);
289edb901aaSMarcel Telka 	}
290edb901aaSMarcel Telka 
291edb901aaSMarcel Telka 	return (ret);
292edb901aaSMarcel Telka }
29389eef05eSrm 
29489eef05eSrm /*
29589eef05eSrm  * mountpoint names must be of the following form:
29689eef05eSrm  *
29789eef05eSrm  *	/[component][/]*[component][/]
298*5ac95da7SSerapheim Dimitropoulos  *
299*5ac95da7SSerapheim Dimitropoulos  * Returns 0 on success, -1 on error.
30089eef05eSrm  */
30189eef05eSrm int
mountpoint_namecheck(const char * path,namecheck_err_t * why)30289eef05eSrm mountpoint_namecheck(const char *path, namecheck_err_t *why)
30389eef05eSrm {
30489eef05eSrm 	const char *start, *end;
30589eef05eSrm 
30689eef05eSrm 	/*
30789eef05eSrm 	 * Make sure none of the mountpoint component names are too long.
30889eef05eSrm 	 * If a component name is too long then the mkdir of the mountpoint
30989eef05eSrm 	 * will fail but then the mountpoint property will be set to a value
31089eef05eSrm 	 * that can never be mounted.  Better to fail before setting the prop.
31189eef05eSrm 	 * Extra slashes are OK, they will be tossed by the mountpoint mkdir.
31289eef05eSrm 	 */
31389eef05eSrm 
31489eef05eSrm 	if (path == NULL || *path != '/') {
31589eef05eSrm 		if (why)
31689eef05eSrm 			*why = NAME_ERR_LEADING_SLASH;
31789eef05eSrm 		return (-1);
31889eef05eSrm 	}
31989eef05eSrm 
32089eef05eSrm 	/* Skip leading slash  */
32189eef05eSrm 	start = &path[1];
32289eef05eSrm 	do {
32389eef05eSrm 		end = start;
32489eef05eSrm 		while (*end != '/' && *end != '\0')
32589eef05eSrm 			end++;
32689eef05eSrm 
3279adfa60dSMatthew Ahrens 		if (end - start >= ZFS_MAX_DATASET_NAME_LEN) {
32889eef05eSrm 			if (why)
32989eef05eSrm 				*why = NAME_ERR_TOOLONG;
33089eef05eSrm 			return (-1);
33189eef05eSrm 		}
33289eef05eSrm 		start = end + 1;
33389eef05eSrm 
33489eef05eSrm 	} while (*end != '\0');
33589eef05eSrm 
33689eef05eSrm 	return (0);
33789eef05eSrm }
33889eef05eSrm 
339fa9e4066Sahrens /*
340fa9e4066Sahrens  * For pool names, we have the same set of valid characters as described in
341fa9e4066Sahrens  * dataset names, with the additional restriction that the pool name must begin
342fa9e4066Sahrens  * with a letter.  The pool names 'raidz' and 'mirror' are also reserved names
343fa9e4066Sahrens  * that cannot be used.
344*5ac95da7SSerapheim Dimitropoulos  *
345*5ac95da7SSerapheim Dimitropoulos  * Returns 0 on success, -1 on error.
346fa9e4066Sahrens  */
347fa9e4066Sahrens int
pool_namecheck(const char * pool,namecheck_err_t * why,char * what)348fa9e4066Sahrens pool_namecheck(const char *pool, namecheck_err_t *why, char *what)
349fa9e4066Sahrens {
350fa9e4066Sahrens 	const char *c;
351fa9e4066Sahrens 
352b81d61a6Slling 	/*
353b81d61a6Slling 	 * Make sure the name is not too long.
354f37ae9a7Sloli 	 * If we're creating a pool with version >= SPA_VERSION_DSL_SCRUB (v11)
355f37ae9a7Sloli 	 * we need to account for additional space needed by the origin ds which
356f37ae9a7Sloli 	 * will also be snapshotted: "poolname"+"/"+"$ORIGIN"+"@"+"$ORIGIN".
357f37ae9a7Sloli 	 * Play it safe and enforce this limit even if the pool version is < 11
358f37ae9a7Sloli 	 * so it can be upgraded without issues.
359b81d61a6Slling 	 */
360f37ae9a7Sloli 	if (strlen(pool) >= (ZFS_MAX_DATASET_NAME_LEN - 2 -
361f37ae9a7Sloli 	    strlen(ORIGIN_DIR_NAME) * 2)) {
362b81d61a6Slling 		if (why)
363b81d61a6Slling 			*why = NAME_ERR_TOOLONG;
364b81d61a6Slling 		return (-1);
365b81d61a6Slling 	}
366b81d61a6Slling 
367fa9e4066Sahrens 	c = pool;
368fa9e4066Sahrens 	while (*c != '\0') {
369fa9e4066Sahrens 		if (!valid_char(*c)) {
370fa9e4066Sahrens 			if (why) {
371fa9e4066Sahrens 				*why = NAME_ERR_INVALCHAR;
372fa9e4066Sahrens 				*what = *c;
373fa9e4066Sahrens 			}
374fa9e4066Sahrens 			return (-1);
375fa9e4066Sahrens 		}
376fa9e4066Sahrens 		c++;
377fa9e4066Sahrens 	}
378fa9e4066Sahrens 
379fa9e4066Sahrens 	if (!(*pool >= 'a' && *pool <= 'z') &&
380fa9e4066Sahrens 	    !(*pool >= 'A' && *pool <= 'Z')) {
381fa9e4066Sahrens 		if (why)
382fa9e4066Sahrens 			*why = NAME_ERR_NOLETTER;
383fa9e4066Sahrens 		return (-1);
384fa9e4066Sahrens 	}
385fa9e4066Sahrens 
386fa9e4066Sahrens 	if (strcmp(pool, "mirror") == 0 || strcmp(pool, "raidz") == 0) {
387fa9e4066Sahrens 		if (why)
388fa9e4066Sahrens 			*why = NAME_ERR_RESERVED;
389fa9e4066Sahrens 		return (-1);
390fa9e4066Sahrens 	}
391fa9e4066Sahrens 
392fa9e4066Sahrens 	if (pool[0] == 'c' && (pool[1] >= '0' && pool[1] <= '9')) {
393fa9e4066Sahrens 		if (why)
394fa9e4066Sahrens 			*why = NAME_ERR_DISKLIKE;
395fa9e4066Sahrens 		return (-1);
396fa9e4066Sahrens 	}
397fa9e4066Sahrens 
398fa9e4066Sahrens 	return (0);
399fa9e4066Sahrens }
400