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