1789Sahrens /*
2789Sahrens * CDDL HEADER START
3789Sahrens *
4789Sahrens * The contents of this file are subject to the terms of the
52199Sahrens * Common Development and Distribution License (the "License").
62199Sahrens * You may not use this file except in compliance with the License.
7789Sahrens *
8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9789Sahrens * or http://www.opensolaris.org/os/licensing.
10789Sahrens * See the License for the specific language governing permissions
11789Sahrens * and limitations under the License.
12789Sahrens *
13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each
14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15789Sahrens * If applicable, add the following below this CDDL HEADER, with the
16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying
17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner]
18789Sahrens *
19789Sahrens * CDDL HEADER END
20789Sahrens */
21789Sahrens /*
229396SMatthew.Ahrens@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23789Sahrens * Use is subject to license terms.
24789Sahrens */
25789Sahrens
26789Sahrens /*
27789Sahrens * Common name validation routines for ZFS. These routines are shared by the
28789Sahrens * userland code as well as the ioctl() layer to ensure that we don't
29789Sahrens * inadvertently expose a hole through direct ioctl()s that never gets tested.
30789Sahrens * In userland, however, we want significantly more information about _why_ the
31789Sahrens * name is invalid. In the kernel, we only care whether it's valid or not.
32789Sahrens * Each routine therefore takes a 'namecheck_err_t' which describes exactly why
33789Sahrens * the name failed to validate.
34789Sahrens *
35789Sahrens * Each function returns 0 on success, -1 on error.
36789Sahrens */
37789Sahrens
38789Sahrens #if defined(_KERNEL)
39789Sahrens #include <sys/systm.h>
40789Sahrens #else
41789Sahrens #include <string.h>
42789Sahrens #endif
43789Sahrens
441003Slling #include <sys/param.h>
454543Smarks #include <sys/nvpair.h>
46789Sahrens #include "zfs_namecheck.h"
474543Smarks #include "zfs_deleg.h"
48789Sahrens
49789Sahrens static int
valid_char(char c)50789Sahrens valid_char(char c)
51789Sahrens {
52789Sahrens return ((c >= 'a' && c <= 'z') ||
53789Sahrens (c >= 'A' && c <= 'Z') ||
54789Sahrens (c >= '0' && c <= '9') ||
556658Smarks c == '-' || c == '_' || c == '.' || c == ':' || c == ' ');
56789Sahrens }
57789Sahrens
58789Sahrens /*
592199Sahrens * Snapshot names must be made up of alphanumeric characters plus the following
602199Sahrens * characters:
612199Sahrens *
62*10242Schris.kirby@sun.com * [-_.: ]
632199Sahrens */
642199Sahrens int
snapshot_namecheck(const char * path,namecheck_err_t * why,char * what)652199Sahrens snapshot_namecheck(const char *path, namecheck_err_t *why, char *what)
662199Sahrens {
672199Sahrens const char *loc;
682199Sahrens
692199Sahrens if (strlen(path) >= MAXNAMELEN) {
702199Sahrens if (why)
712199Sahrens *why = NAME_ERR_TOOLONG;
722199Sahrens return (-1);
732199Sahrens }
742199Sahrens
752199Sahrens if (path[0] == '\0') {
762199Sahrens if (why)
772199Sahrens *why = NAME_ERR_EMPTY_COMPONENT;
782199Sahrens return (-1);
792199Sahrens }
802199Sahrens
812199Sahrens for (loc = path; *loc; loc++) {
822199Sahrens if (!valid_char(*loc)) {
832199Sahrens if (why) {
842199Sahrens *why = NAME_ERR_INVALCHAR;
852199Sahrens *what = *loc;
862199Sahrens }
872199Sahrens return (-1);
882199Sahrens }
892199Sahrens }
902199Sahrens return (0);
912199Sahrens }
922199Sahrens
934543Smarks
944543Smarks /*
954543Smarks * Permissions set name must start with the letter '@' followed by the
964543Smarks * same character restrictions as snapshot names, except that the name
974543Smarks * cannot exceed 64 characters.
984543Smarks */
994543Smarks int
permset_namecheck(const char * path,namecheck_err_t * why,char * what)1004543Smarks permset_namecheck(const char *path, namecheck_err_t *why, char *what)
1014543Smarks {
1024543Smarks if (strlen(path) >= ZFS_PERMSET_MAXLEN) {
1034543Smarks if (why)
1044543Smarks *why = NAME_ERR_TOOLONG;
1054543Smarks return (-1);
1064543Smarks }
1074543Smarks
1084543Smarks if (path[0] != '@') {
1094543Smarks if (why) {
1104543Smarks *why = NAME_ERR_NO_AT;
1114543Smarks *what = path[0];
1124543Smarks }
1134543Smarks return (-1);
1144543Smarks }
1154543Smarks
1164543Smarks return (snapshot_namecheck(&path[1], why, what));
1174543Smarks }
1184543Smarks
1192199Sahrens /*
120789Sahrens * Dataset names must be of the following form:
121789Sahrens *
122789Sahrens * [component][/]*[component][@component]
123789Sahrens *
124789Sahrens * Where each component is made up of alphanumeric characters plus the following
125789Sahrens * characters:
126789Sahrens *
1275326Sek110237 * [-_.:%]
1285348Sek110237 *
1295348Sek110237 * We allow '%' here as we use that character internally to create unique
1305348Sek110237 * names for temporary clones (for online recv).
131789Sahrens */
132789Sahrens int
dataset_namecheck(const char * path,namecheck_err_t * why,char * what)133789Sahrens dataset_namecheck(const char *path, namecheck_err_t *why, char *what)
134789Sahrens {
135789Sahrens const char *loc, *end;
136789Sahrens int found_snapshot;
137789Sahrens
1381003Slling /*
1391003Slling * Make sure the name is not too long.
1401003Slling *
1411003Slling * ZFS_MAXNAMELEN is the maximum dataset length used in the userland
1421003Slling * which is the same as MAXNAMELEN used in the kernel.
1431003Slling * If ZFS_MAXNAMELEN value is changed, make sure to cleanup all
1441003Slling * places using MAXNAMELEN.
1451003Slling */
1464543Smarks
1471003Slling if (strlen(path) >= MAXNAMELEN) {
1481003Slling if (why)
1491003Slling *why = NAME_ERR_TOOLONG;
1501003Slling return (-1);
1511003Slling }
1521003Slling
153789Sahrens /* Explicitly check for a leading slash. */
154789Sahrens if (path[0] == '/') {
155789Sahrens if (why)
156789Sahrens *why = NAME_ERR_LEADING_SLASH;
157789Sahrens return (-1);
158789Sahrens }
159789Sahrens
160789Sahrens if (path[0] == '\0') {
161789Sahrens if (why)
162789Sahrens *why = NAME_ERR_EMPTY_COMPONENT;
163789Sahrens return (-1);
164789Sahrens }
165789Sahrens
166789Sahrens loc = path;
167789Sahrens found_snapshot = 0;
168789Sahrens for (;;) {
169789Sahrens /* Find the end of this component */
170789Sahrens end = loc;
171789Sahrens while (*end != '/' && *end != '@' && *end != '\0')
172789Sahrens end++;
173789Sahrens
174789Sahrens if (*end == '\0' && end[-1] == '/') {
175789Sahrens /* trailing slashes are not allowed */
176789Sahrens if (why)
177789Sahrens *why = NAME_ERR_TRAILING_SLASH;
178789Sahrens return (-1);
179789Sahrens }
180789Sahrens
181789Sahrens /* Zero-length components are not allowed */
1823394Spd144616 if (loc == end) {
1833394Spd144616 if (why) {
1843394Spd144616 /*
1853394Spd144616 * Make sure this is really a zero-length
1863394Spd144616 * component and not a '@@'.
1873394Spd144616 */
1883394Spd144616 if (*end == '@' && found_snapshot) {
1893394Spd144616 *why = NAME_ERR_MULTIPLE_AT;
1903394Spd144616 } else {
1913394Spd144616 *why = NAME_ERR_EMPTY_COMPONENT;
1923394Spd144616 }
1933394Spd144616 }
1943394Spd144616
195789Sahrens return (-1);
196789Sahrens }
197789Sahrens
198789Sahrens /* Validate the contents of this component */
199789Sahrens while (loc != end) {
2005348Sek110237 if (!valid_char(*loc) && *loc != '%') {
201789Sahrens if (why) {
202789Sahrens *why = NAME_ERR_INVALCHAR;
203789Sahrens *what = *loc;
204789Sahrens }
205789Sahrens return (-1);
206789Sahrens }
207789Sahrens loc++;
208789Sahrens }
209789Sahrens
210789Sahrens /* If we've reached the end of the string, we're OK */
211789Sahrens if (*end == '\0')
212789Sahrens return (0);
213789Sahrens
214789Sahrens if (*end == '@') {
215789Sahrens /*
216789Sahrens * If we've found an @ symbol, indicate that we're in
217789Sahrens * the snapshot component, and report a second '@'
218789Sahrens * character as an error.
219789Sahrens */
220789Sahrens if (found_snapshot) {
221789Sahrens if (why)
222789Sahrens *why = NAME_ERR_MULTIPLE_AT;
223789Sahrens return (-1);
224789Sahrens }
225789Sahrens
226789Sahrens found_snapshot = 1;
227789Sahrens }
228789Sahrens
2292665Snd150628 /*
2302665Snd150628 * If there is a '/' in a snapshot name
2312665Snd150628 * then report an error
2322665Snd150628 */
2332665Snd150628 if (*end == '/' && found_snapshot) {
2342665Snd150628 if (why)
2352665Snd150628 *why = NAME_ERR_TRAILING_SLASH;
2362665Snd150628 return (-1);
2372665Snd150628 }
2382665Snd150628
239789Sahrens /* Update to the next component */
240789Sahrens loc = end + 1;
241789Sahrens }
242789Sahrens }
243789Sahrens
2444778Srm160521
2454778Srm160521 /*
2464778Srm160521 * mountpoint names must be of the following form:
2474778Srm160521 *
2484778Srm160521 * /[component][/]*[component][/]
2494778Srm160521 */
2504778Srm160521 int
mountpoint_namecheck(const char * path,namecheck_err_t * why)2514778Srm160521 mountpoint_namecheck(const char *path, namecheck_err_t *why)
2524778Srm160521 {
2534778Srm160521 const char *start, *end;
2544778Srm160521
2554778Srm160521 /*
2564778Srm160521 * Make sure none of the mountpoint component names are too long.
2574778Srm160521 * If a component name is too long then the mkdir of the mountpoint
2584778Srm160521 * will fail but then the mountpoint property will be set to a value
2594778Srm160521 * that can never be mounted. Better to fail before setting the prop.
2604778Srm160521 * Extra slashes are OK, they will be tossed by the mountpoint mkdir.
2614778Srm160521 */
2624778Srm160521
2634778Srm160521 if (path == NULL || *path != '/') {
2644778Srm160521 if (why)
2654778Srm160521 *why = NAME_ERR_LEADING_SLASH;
2664778Srm160521 return (-1);
2674778Srm160521 }
2684778Srm160521
2694778Srm160521 /* Skip leading slash */
2704778Srm160521 start = &path[1];
2714778Srm160521 do {
2724778Srm160521 end = start;
2734778Srm160521 while (*end != '/' && *end != '\0')
2744778Srm160521 end++;
2754778Srm160521
2764778Srm160521 if (end - start >= MAXNAMELEN) {
2774778Srm160521 if (why)
2784778Srm160521 *why = NAME_ERR_TOOLONG;
2794778Srm160521 return (-1);
2804778Srm160521 }
2814778Srm160521 start = end + 1;
2824778Srm160521
2834778Srm160521 } while (*end != '\0');
2844778Srm160521
2854778Srm160521 return (0);
2864778Srm160521 }
2874778Srm160521
288789Sahrens /*
289789Sahrens * For pool names, we have the same set of valid characters as described in
290789Sahrens * dataset names, with the additional restriction that the pool name must begin
291789Sahrens * with a letter. The pool names 'raidz' and 'mirror' are also reserved names
292789Sahrens * that cannot be used.
293789Sahrens */
294789Sahrens int
pool_namecheck(const char * pool,namecheck_err_t * why,char * what)295789Sahrens pool_namecheck(const char *pool, namecheck_err_t *why, char *what)
296789Sahrens {
297789Sahrens const char *c;
298789Sahrens
2991003Slling /*
3001003Slling * Make sure the name is not too long.
3011003Slling *
3021003Slling * ZPOOL_MAXNAMELEN is the maximum pool length used in the userland
3031003Slling * which is the same as MAXNAMELEN used in the kernel.
3041003Slling * If ZPOOL_MAXNAMELEN value is changed, make sure to cleanup all
3051003Slling * places using MAXNAMELEN.
3061003Slling */
3071003Slling if (strlen(pool) >= MAXNAMELEN) {
3081003Slling if (why)
3091003Slling *why = NAME_ERR_TOOLONG;
3101003Slling return (-1);
3111003Slling }
3121003Slling
313789Sahrens c = pool;
314789Sahrens while (*c != '\0') {
315789Sahrens if (!valid_char(*c)) {
316789Sahrens if (why) {
317789Sahrens *why = NAME_ERR_INVALCHAR;
318789Sahrens *what = *c;
319789Sahrens }
320789Sahrens return (-1);
321789Sahrens }
322789Sahrens c++;
323789Sahrens }
324789Sahrens
325789Sahrens if (!(*pool >= 'a' && *pool <= 'z') &&
326789Sahrens !(*pool >= 'A' && *pool <= 'Z')) {
327789Sahrens if (why)
328789Sahrens *why = NAME_ERR_NOLETTER;
329789Sahrens return (-1);
330789Sahrens }
331789Sahrens
332789Sahrens if (strcmp(pool, "mirror") == 0 || strcmp(pool, "raidz") == 0) {
333789Sahrens if (why)
334789Sahrens *why = NAME_ERR_RESERVED;
335789Sahrens return (-1);
336789Sahrens }
337789Sahrens
338789Sahrens if (pool[0] == 'c' && (pool[1] >= '0' && pool[1] <= '9')) {
339789Sahrens if (why)
340789Sahrens *why = NAME_ERR_DISKLIKE;
341789Sahrens return (-1);
342789Sahrens }
343789Sahrens
344789Sahrens return (0);
345789Sahrens }
346