Home | History | Annotate | Download | only in zfs
      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 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27 
     28 /*
     29  * Common name validation routines for ZFS.  These routines are shared by the
     30  * userland code as well as the ioctl() layer to ensure that we don't
     31  * inadvertently expose a hole through direct ioctl()s that never gets tested.
     32  * In userland, however, we want significantly more information about _why_ the
     33  * name is invalid.  In the kernel, we only care whether it's valid or not.
     34  * Each routine therefore takes a 'namecheck_err_t' which describes exactly why
     35  * the name failed to validate.
     36  *
     37  * Each function returns 0 on success, -1 on error.
     38  */
     39 
     40 #if defined(_KERNEL)
     41 #include <sys/systm.h>
     42 #else
     43 #include <string.h>
     44 #endif
     45 
     46 #include <sys/param.h>
     47 #include <sys/nvpair.h>
     48 #include "zfs_namecheck.h"
     49 #include "zfs_deleg.h"
     50 
     51 static int
     52 valid_char(char c)
     53 {
     54 	return ((c >= 'a' && c <= 'z') ||
     55 	    (c >= 'A' && c <= 'Z') ||
     56 	    (c >= '0' && c <= '9') ||
     57 	    c == '-' || c == '_' || c == '.' || c == ':' || c == ' ');
     58 }
     59 
     60 /*
     61  * Snapshot names must be made up of alphanumeric characters plus the following
     62  * characters:
     63  *
     64  * 	[-_.:]
     65  */
     66 int
     67 snapshot_namecheck(const char *path, namecheck_err_t *why, char *what)
     68 {
     69 	const char *loc;
     70 
     71 	if (strlen(path) >= MAXNAMELEN) {
     72 		if (why)
     73 			*why = NAME_ERR_TOOLONG;
     74 		return (-1);
     75 	}
     76 
     77 	if (path[0] == '\0') {
     78 		if (why)
     79 			*why = NAME_ERR_EMPTY_COMPONENT;
     80 		return (-1);
     81 	}
     82 
     83 	for (loc = path; *loc; loc++) {
     84 		if (!valid_char(*loc)) {
     85 			if (why) {
     86 				*why = NAME_ERR_INVALCHAR;
     87 				*what = *loc;
     88 			}
     89 			return (-1);
     90 		}
     91 	}
     92 	return (0);
     93 }
     94 
     95 
     96 /*
     97  * Permissions set name must start with the letter '@' followed by the
     98  * same character restrictions as snapshot names, except that the name
     99  * cannot exceed 64 characters.
    100  */
    101 int
    102 permset_namecheck(const char *path, namecheck_err_t *why, char *what)
    103 {
    104 	if (strlen(path) >= ZFS_PERMSET_MAXLEN) {
    105 		if (why)
    106 			*why = NAME_ERR_TOOLONG;
    107 		return (-1);
    108 	}
    109 
    110 	if (path[0] != '@') {
    111 		if (why) {
    112 			*why = NAME_ERR_NO_AT;
    113 			*what = path[0];
    114 		}
    115 		return (-1);
    116 	}
    117 
    118 	return (snapshot_namecheck(&path[1], why, what));
    119 }
    120 
    121 /*
    122  * Dataset names must be of the following form:
    123  *
    124  * 	[component][/]*[component][@component]
    125  *
    126  * Where each component is made up of alphanumeric characters plus the following
    127  * characters:
    128  *
    129  * 	[-_.:%]
    130  *
    131  * We allow '%' here as we use that character internally to create unique
    132  * names for temporary clones (for online recv).
    133  */
    134 int
    135 dataset_namecheck(const char *path, namecheck_err_t *why, char *what)
    136 {
    137 	const char *loc, *end;
    138 	int found_snapshot;
    139 
    140 	/*
    141 	 * Make sure the name is not too long.
    142 	 *
    143 	 * ZFS_MAXNAMELEN is the maximum dataset length used in the userland
    144 	 * which is the same as MAXNAMELEN used in the kernel.
    145 	 * If ZFS_MAXNAMELEN value is changed, make sure to cleanup all
    146 	 * places using MAXNAMELEN.
    147 	 */
    148 
    149 	if (strlen(path) >= MAXNAMELEN) {
    150 		if (why)
    151 			*why = NAME_ERR_TOOLONG;
    152 		return (-1);
    153 	}
    154 
    155 	/* Explicitly check for a leading slash.  */
    156 	if (path[0] == '/') {
    157 		if (why)
    158 			*why = NAME_ERR_LEADING_SLASH;
    159 		return (-1);
    160 	}
    161 
    162 	if (path[0] == '\0') {
    163 		if (why)
    164 			*why = NAME_ERR_EMPTY_COMPONENT;
    165 		return (-1);
    166 	}
    167 
    168 	loc = path;
    169 	found_snapshot = 0;
    170 	for (;;) {
    171 		/* Find the end of this component */
    172 		end = loc;
    173 		while (*end != '/' && *end != '@' && *end != '\0')
    174 			end++;
    175 
    176 		if (*end == '\0' && end[-1] == '/') {
    177 			/* trailing slashes are not allowed */
    178 			if (why)
    179 				*why = NAME_ERR_TRAILING_SLASH;
    180 			return (-1);
    181 		}
    182 
    183 		/* Zero-length components are not allowed */
    184 		if (loc == end) {
    185 			if (why) {
    186 				/*
    187 				 * Make sure this is really a zero-length
    188 				 * component and not a '@@'.
    189 				 */
    190 				if (*end == '@' && found_snapshot) {
    191 					*why = NAME_ERR_MULTIPLE_AT;
    192 				} else {
    193 					*why = NAME_ERR_EMPTY_COMPONENT;
    194 				}
    195 			}
    196 
    197 			return (-1);
    198 		}
    199 
    200 		/* Validate the contents of this component */
    201 		while (loc != end) {
    202 			if (!valid_char(*loc) && *loc != '%') {
    203 				if (why) {
    204 					*why = NAME_ERR_INVALCHAR;
    205 					*what = *loc;
    206 				}
    207 				return (-1);
    208 			}
    209 			loc++;
    210 		}
    211 
    212 		/* If we've reached the end of the string, we're OK */
    213 		if (*end == '\0')
    214 			return (0);
    215 
    216 		if (*end == '@') {
    217 			/*
    218 			 * If we've found an @ symbol, indicate that we're in
    219 			 * the snapshot component, and report a second '@'
    220 			 * character as an error.
    221 			 */
    222 			if (found_snapshot) {
    223 				if (why)
    224 					*why = NAME_ERR_MULTIPLE_AT;
    225 				return (-1);
    226 			}
    227 
    228 			found_snapshot = 1;
    229 		}
    230 
    231 		/*
    232 		 * If there is a '/' in a snapshot name
    233 		 * then report an error
    234 		 */
    235 		if (*end == '/' && found_snapshot) {
    236 			if (why)
    237 				*why = NAME_ERR_TRAILING_SLASH;
    238 			return (-1);
    239 		}
    240 
    241 		/* Update to the next component */
    242 		loc = end + 1;
    243 	}
    244 }
    245 
    246 
    247 /*
    248  * mountpoint names must be of the following form:
    249  *
    250  *	/[component][/]*[component][/]
    251  */
    252 int
    253 mountpoint_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 
    278 		if (end - start >= MAXNAMELEN) {
    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  */
    296 int
    297 pool_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.
    303 	 *
    304 	 * ZPOOL_MAXNAMELEN is the maximum pool length used in the userland
    305 	 * which is the same as MAXNAMELEN used in the kernel.
    306 	 * If ZPOOL_MAXNAMELEN value is changed, make sure to cleanup all
    307 	 * places using MAXNAMELEN.
    308 	 */
    309 	if (strlen(pool) >= MAXNAMELEN) {
    310 		if (why)
    311 			*why = NAME_ERR_TOOLONG;
    312 		return (-1);
    313 	}
    314 
    315 	c = pool;
    316 	while (*c != '\0') {
    317 		if (!valid_char(*c)) {
    318 			if (why) {
    319 				*why = NAME_ERR_INVALCHAR;
    320 				*what = *c;
    321 			}
    322 			return (-1);
    323 		}
    324 		c++;
    325 	}
    326 
    327 	if (!(*pool >= 'a' && *pool <= 'z') &&
    328 	    !(*pool >= 'A' && *pool <= 'Z')) {
    329 		if (why)
    330 			*why = NAME_ERR_NOLETTER;
    331 		return (-1);
    332 	}
    333 
    334 	if (strcmp(pool, "mirror") == 0 || strcmp(pool, "raidz") == 0) {
    335 		if (why)
    336 			*why = NAME_ERR_RESERVED;
    337 		return (-1);
    338 	}
    339 
    340 	if (pool[0] == 'c' && (pool[1] >= '0' && pool[1] <= '9')) {
    341 		if (why)
    342 			*why = NAME_ERR_DISKLIKE;
    343 		return (-1);
    344 	}
    345 
    346 	return (0);
    347 }
    348 
    349 /*
    350  * Check if the dataset name is private for internal usage.
    351  * '$' is reserved for internal dataset names. e.g. "$MOS"
    352  *
    353  * Return 1 if the given name is used internally.
    354  * Return 0 if it is not.
    355  */
    356 int
    357 dataset_name_hidden(const char *name)
    358 {
    359 	if (strchr(name, '$') != NULL)
    360 		return (1);
    361 
    362 	return (0);
    363 }
    364