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