zfs_namecheck.c revision 325910
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 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 * Each function returns 0 on success, -1 on error.
39 */
40
41#if defined(_KERNEL)
42#include <sys/systm.h>
43#else
44#include <string.h>
45#endif
46
47#include <sys/dsl_dir.h>
48#include <sys/param.h>
49#include <sys/nvpair.h>
50#include "zfs_namecheck.h"
51#include "zfs_deleg.h"
52
53static int
54valid_char(char c)
55{
56	return ((c >= 'a' && c <= 'z') ||
57	    (c >= 'A' && c <= 'Z') ||
58	    (c >= '0' && c <= '9') ||
59	    c == '-' || c == '_' || c == '.' || c == ':' || c == ' ');
60}
61
62/*
63 * Snapshot names must be made up of alphanumeric characters plus the following
64 * characters:
65 *
66 * 	[-_.: ]
67 */
68int
69zfs_component_namecheck(const char *path, namecheck_err_t *why, char *what)
70{
71	const char *loc;
72
73	if (strlen(path) >= ZFS_MAX_DATASET_NAME_LEN) {
74		if (why)
75			*why = NAME_ERR_TOOLONG;
76		return (-1);
77	}
78
79	if (path[0] == '\0') {
80		if (why)
81			*why = NAME_ERR_EMPTY_COMPONENT;
82		return (-1);
83	}
84
85	for (loc = path; *loc; loc++) {
86		if (!valid_char(*loc)) {
87			if (why) {
88				*why = NAME_ERR_INVALCHAR;
89				*what = *loc;
90			}
91			return (-1);
92		}
93	}
94	return (0);
95}
96
97
98/*
99 * Permissions set name must start with the letter '@' followed by the
100 * same character restrictions as snapshot names, except that the name
101 * cannot exceed 64 characters.
102 */
103int
104permset_namecheck(const char *path, namecheck_err_t *why, char *what)
105{
106	if (strlen(path) >= ZFS_PERMSET_MAXLEN) {
107		if (why)
108			*why = NAME_ERR_TOOLONG;
109		return (-1);
110	}
111
112	if (path[0] != '@') {
113		if (why) {
114			*why = NAME_ERR_NO_AT;
115			*what = path[0];
116		}
117		return (-1);
118	}
119
120	return (zfs_component_namecheck(&path[1], why, what));
121}
122
123/*
124 * Dataset names must be of the following form:
125 *
126 * 	[component][/]*[component][@component]
127 *
128 * Where each component is made up of alphanumeric characters plus the following
129 * characters:
130 *
131 * 	[-_.:%]
132 *
133 * We allow '%' here as we use that character internally to create unique
134 * names for temporary clones (for online recv).
135 */
136int
137dataset_namecheck(const char *path, namecheck_err_t *why, char *what)
138{
139	const char *loc, *end;
140	int found_snapshot;
141
142	/*
143	 * Make sure the name is not too long.
144	 */
145
146	if (strlen(path) >= ZFS_MAX_DATASET_NAME_LEN) {
147		if (why)
148			*why = NAME_ERR_TOOLONG;
149		return (-1);
150	}
151
152	/* Explicitly check for a leading slash.  */
153	if (path[0] == '/') {
154		if (why)
155			*why = NAME_ERR_LEADING_SLASH;
156		return (-1);
157	}
158
159	if (path[0] == '\0') {
160		if (why)
161			*why = NAME_ERR_EMPTY_COMPONENT;
162		return (-1);
163	}
164
165	loc = path;
166	found_snapshot = 0;
167	for (;;) {
168		/* Find the end of this component */
169		end = loc;
170		while (*end != '/' && *end != '@' && *end != '\0')
171			end++;
172
173		if (*end == '\0' && end[-1] == '/') {
174			/* trailing slashes are not allowed */
175			if (why)
176				*why = NAME_ERR_TRAILING_SLASH;
177			return (-1);
178		}
179
180		/* Zero-length components are not allowed */
181		if (loc == end) {
182			if (why) {
183				/*
184				 * Make sure this is really a zero-length
185				 * component and not a '@@'.
186				 */
187				if (*end == '@' && found_snapshot) {
188					*why = NAME_ERR_MULTIPLE_AT;
189				} else {
190					*why = NAME_ERR_EMPTY_COMPONENT;
191				}
192			}
193
194			return (-1);
195		}
196
197		/* Validate the contents of this component */
198		while (loc != end) {
199			if (!valid_char(*loc) && *loc != '%') {
200				if (why) {
201					*why = NAME_ERR_INVALCHAR;
202					*what = *loc;
203				}
204				return (-1);
205			}
206			loc++;
207		}
208
209		/* If we've reached the end of the string, we're OK */
210		if (*end == '\0')
211			return (0);
212
213		if (*end == '@') {
214			/*
215			 * If we've found an @ symbol, indicate that we're in
216			 * the snapshot component, and report a second '@'
217			 * character as an error.
218			 */
219			if (found_snapshot) {
220				if (why)
221					*why = NAME_ERR_MULTIPLE_AT;
222				return (-1);
223			}
224
225			found_snapshot = 1;
226		}
227
228		/*
229		 * If there is a '/' in a snapshot name
230		 * then report an error
231		 */
232		if (*end == '/' && found_snapshot) {
233			if (why)
234				*why = NAME_ERR_TRAILING_SLASH;
235			return (-1);
236		}
237
238		/* Update to the next component */
239		loc = end + 1;
240	}
241}
242
243
244/*
245 * mountpoint names must be of the following form:
246 *
247 *	/[component][/]*[component][/]
248 */
249int
250mountpoint_namecheck(const char *path, namecheck_err_t *why)
251{
252	const char *start, *end;
253
254	/*
255	 * Make sure none of the mountpoint component names are too long.
256	 * If a component name is too long then the mkdir of the mountpoint
257	 * will fail but then the mountpoint property will be set to a value
258	 * that can never be mounted.  Better to fail before setting the prop.
259	 * Extra slashes are OK, they will be tossed by the mountpoint mkdir.
260	 */
261
262	if (path == NULL || *path != '/') {
263		if (why)
264			*why = NAME_ERR_LEADING_SLASH;
265		return (-1);
266	}
267
268	/* Skip leading slash  */
269	start = &path[1];
270	do {
271		end = start;
272		while (*end != '/' && *end != '\0')
273			end++;
274
275		if (end - start >= ZFS_MAX_DATASET_NAME_LEN) {
276			if (why)
277				*why = NAME_ERR_TOOLONG;
278			return (-1);
279		}
280		start = end + 1;
281
282	} while (*end != '\0');
283
284	return (0);
285}
286
287/*
288 * For pool names, we have the same set of valid characters as described in
289 * dataset names, with the additional restriction that the pool name must begin
290 * with a letter.  The pool names 'raidz' and 'mirror' are also reserved names
291 * that cannot be used.
292 */
293int
294pool_namecheck(const char *pool, namecheck_err_t *why, char *what)
295{
296	const char *c;
297
298	/*
299	 * Make sure the name is not too long.
300	 * If we're creating a pool with version >= SPA_VERSION_DSL_SCRUB (v11)
301	 * we need to account for additional space needed by the origin ds which
302	 * will also be snapshotted: "poolname"+"/"+"$ORIGIN"+"@"+"$ORIGIN".
303	 * Play it safe and enforce this limit even if the pool version is < 11
304	 * so it can be upgraded without issues.
305	 */
306	if (strlen(pool) >= (ZFS_MAX_DATASET_NAME_LEN - 2 -
307	    strlen(ORIGIN_DIR_NAME) * 2)) {
308		if (why)
309			*why = NAME_ERR_TOOLONG;
310		return (-1);
311	}
312
313	c = pool;
314	while (*c != '\0') {
315		if (!valid_char(*c)) {
316			if (why) {
317				*why = NAME_ERR_INVALCHAR;
318				*what = *c;
319			}
320			return (-1);
321		}
322		c++;
323	}
324
325	if (!(*pool >= 'a' && *pool <= 'z') &&
326	    !(*pool >= 'A' && *pool <= 'Z')) {
327		if (why)
328			*why = NAME_ERR_NOLETTER;
329		return (-1);
330	}
331
332	if (strcmp(pool, "mirror") == 0 || strcmp(pool, "raidz") == 0) {
333		if (why)
334			*why = NAME_ERR_RESERVED;
335		return (-1);
336	}
337
338	if (pool[0] == 'c' && (pool[1] >= '0' && pool[1] <= '9')) {
339		if (why)
340			*why = NAME_ERR_DISKLIKE;
341		return (-1);
342	}
343
344	return (0);
345}
346