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