diff --git a/lib/libc/gen/setmode.3 b/lib/libc/gen/setmode.3 index f22019e0dd9d..b76e88c240e2 100644 --- a/lib/libc/gen/setmode.3 +++ b/lib/libc/gen/setmode.3 @@ -1,4 +1,4 @@ -.\" $NetBSD: setmode.3,v 1.17 2005/06/04 00:39:26 wiz Exp $ +.\" $NetBSD: setmode.3,v 1.18 2005/10/01 20:08:01 christos Exp $ .\" .\" Copyright (c) 1989, 1991, 1993 .\" The Regents of the University of California. All rights reserved. @@ -29,7 +29,7 @@ .\" .\" @(#)setmode.3 8.2 (Berkeley) 4/28/95 .\" -.Dd May 17, 2005 +.Dd October 1, 2005 .Dt SETMODE 3 .Os .Sh NAME @@ -95,6 +95,17 @@ for any of the errors specified for the library routines .Xr malloc 3 or .Xr strtol 3 . +In addition, +.Fn setmode +will fail and set +.Va errno +to: +.Bl -tag -width Er +.It Bq Er EINVAL +The +.Fa mode +argument does not represent a valid mode. +.El .Sh SEE ALSO .Xr chmod 1 , .Xr stat 2 , diff --git a/lib/libc/gen/setmode.c b/lib/libc/gen/setmode.c index 54ed8e7535b4..83dd752b9979 100644 --- a/lib/libc/gen/setmode.c +++ b/lib/libc/gen/setmode.c @@ -1,4 +1,4 @@ -/* $NetBSD: setmode.c,v 1.30 2003/08/07 16:42:56 agc Exp $ */ +/* $NetBSD: setmode.c,v 1.31 2005/10/01 20:08:01 christos Exp $ */ /* * Copyright (c) 1989, 1993, 1994 @@ -37,7 +37,7 @@ #if 0 static char sccsid[] = "@(#)setmode.c 8.2 (Berkeley) 3/25/94"; #else -__RCSID("$NetBSD: setmode.c,v 1.30 2003/08/07 16:42:56 agc Exp $"); +__RCSID("$NetBSD: setmode.c,v 1.31 2005/10/01 20:08:01 christos Exp $"); #endif #endif /* LIBC_SCCS and not lint */ @@ -50,6 +50,7 @@ __RCSID("$NetBSD: setmode.c,v 1.30 2003/08/07 16:42:56 agc Exp $"); #include #include #include +#include #include #ifdef SETMODE_DEBUG @@ -76,7 +77,7 @@ typedef struct bitcmd { #define CMD2_OBITS 0x08 #define CMD2_UBITS 0x10 -static BITCMD *addcmd __P((BITCMD *, int, int, int, u_int)); +static BITCMD *addcmd __P((BITCMD *, mode_t, mode_t, mode_t, mode_t)); static void compress_mode __P((BITCMD *)); #ifdef SETMODE_DEBUG static void dumpmode __P((BITCMD *)); @@ -165,15 +166,13 @@ common: if (set->cmd2 & CMD2_CLR) { BITCMD *newset; \ setlen += SET_LEN_INCR; \ newset = realloc(saveset, sizeof(BITCMD) * setlen); \ - if (newset == NULL) { \ - free(saveset); \ - return (NULL); \ - } \ + if (newset == NULL) \ + goto out; \ set = newset + (set - saveset); \ saveset = newset; \ endset = newset + (setlen - 2); \ } \ - set = addcmd(set, (a), (b), (c), (d)); \ + set = addcmd(set, (mode_t)(a), (mode_t)(b), (mode_t)(c), (d)); \ } while (/*CONSTCOND*/0) #define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) @@ -182,16 +181,19 @@ void * setmode(p) const char *p; { - int perm, who; + int serrno; char op, *ep; BITCMD *set, *saveset, *endset; sigset_t signset, sigoset; - mode_t mask; + mode_t mask, perm, permXbits, who; + long lval; int equalopdone = 0; /* pacify gcc */ - int permXbits, setlen; + int setlen; - if (!*p) - return (NULL); + if (!*p) { + errno = EINVAL; + return NULL; + } /* * Get a copy of the mask for the permissions that are mask relative. @@ -217,11 +219,19 @@ setmode(p) * or illegal bits. */ if (isdigit((unsigned char)*p)) { - perm = (mode_t)strtol(p, &ep, 8); - if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) { - free(saveset); - return (NULL); + errno = 0; + lval = strtol(p, &ep, 8); + if (*ep) { + errno = EINVAL; + goto out; } + if (errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN)) + goto out; + if (lval & ~(STANDARD_BITS|S_ISTXT)) { + errno = EINVAL; + goto out; + } + perm = (mode_t)lval; ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask); set->cmd = 0; return (saveset); @@ -253,8 +263,8 @@ setmode(p) } getop: if ((op = *p++) != '+' && op != '-' && op != '=') { - free(saveset); - return (NULL); + errno = EINVAL; + goto out; } if (op == '=') equalopdone = 0; @@ -349,14 +359,17 @@ apply: if (!*p) dumpmode(saveset); #endif return (saveset); +out: + serrno = errno; + free(saveset); + errno = serrno; + return NULL; } static BITCMD * addcmd(set, op, who, oparg, mask) BITCMD *set; - int oparg, who; - int op; - u_int mask; + mode_t oparg, who, op, mask; { _DIAGASSERT(set != NULL);