1: /*
   2:  * Copyright (c) 1989, 1993, 1994
   3:  *	The Regents of the University of California.  All rights reserved.
   4:  *
   5:  * This code is derived from software contributed to Berkeley by
   6:  * Dave Borman at Cray Research, Inc.
   7:  *
   8:  * Redistribution and use in source and binary forms, with or without
   9:  * modification, are permitted provided that the following conditions
  10:  * are met:
  11:  * 1. Redistributions of source code must retain the above copyright
  12:  *    notice, this list of conditions and the following disclaimer.
  13:  * 2. Redistributions in binary form must reproduce the above copyright
  14:  *    notice, this list of conditions and the following disclaimer in the
  15:  *    documentation and/or other materials provided with the distribution.
  16:  * 3. All advertising materials mentioning features or use of this software
  17:  *    must display the following acknowledgement:
  18:  *	This product includes software developed by the University of
  19:  *	California, Berkeley and its contributors.
  20:  * 4. Neither the name of the University nor the names of its contributors
  21:  *    may be used to endorse or promote products derived from this software
  22:  *    without specific prior written permission.
  23:  *
  24:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34:  * SUCH DAMAGE.
  35:  */
  36: 
  37: #if defined(LIBC_SCCS) && !defined(lint)
  38: static char sccsid[] = "@(#)setmode.c	8.2.1 (2.11BSD) 1996/2/20";
  39: #endif /* LIBC_SCCS and not lint */
  40: 
  41: #include <sys/types.h>
  42: #include <sys/stat.h>
  43: 
  44: #include <ctype.h>
  45: #include <errno.h>
  46: #include <signal.h>
  47: #include <sys/stddef.h>
  48: #include <stdlib.h>
  49: 
  50: #ifdef SETMODE_DEBUG
  51: #include <stdio.h>
  52: #endif
  53: 
  54: #define SET_LEN 6       /* initial # of bitcmd struct to malloc */
  55: #define SET_LEN_INCR 4      /* # of bitcmd structs to add as needed */
  56: 
  57: typedef struct bitcmd {
  58:     char    cmd;
  59:     char    cmd2;
  60:     mode_t  bits;
  61: } BITCMD;
  62: 
  63: #define CMD2_CLR    0x01
  64: #define CMD2_SET    0x02
  65: #define CMD2_GBITS  0x04
  66: #define CMD2_OBITS  0x08
  67: #define CMD2_UBITS  0x10
  68: 
  69: static BITCMD   *addcmd();
  70: static int   compress_mode();
  71: #ifdef SETMODE_DEBUG
  72: static void  dumpmode();
  73: #endif
  74: 
  75: /*
  76:  * Given the old mode and an array of bitcmd structures, apply the operations
  77:  * described in the bitcmd structures to the old mode, and return the new mode.
  78:  * Note that there is no '=' command; a strict assignment is just a '-' (clear
  79:  * bits) followed by a '+' (set bits).
  80:  */
  81: mode_t
  82: getmode(bbox, omode)
  83:     void *bbox;
  84:     mode_t omode;
  85: {
  86:     register BITCMD *set;
  87:     register mode_t clrval, newmode, value;
  88: 
  89:     set = (BITCMD *)bbox;
  90:     newmode = omode;
  91:     for (value = 0;; set++)
  92:         switch(set->cmd) {
  93:         /*
  94: 		 * When copying the user, group or other bits around, we "know"
  95: 		 * where the bits are in the mode so that we can do shifts to
  96: 		 * copy them around.  If we don't use shifts, it gets real
  97: 		 * grundgy with lots of single bit checks and bit sets.
  98: 		 */
  99:         case 'u':
 100:             value = (newmode & S_IRWXU) >> 6;
 101:             goto common;
 102: 
 103:         case 'g':
 104:             value = (newmode & S_IRWXG) >> 3;
 105:             goto common;
 106: 
 107:         case 'o':
 108:             value = newmode & S_IRWXO;
 109: common:         if (set->cmd2 & CMD2_CLR) {
 110:                 clrval =
 111:                     (set->cmd2 & CMD2_SET) ?  S_IRWXO : value;
 112:                 if (set->cmd2 & CMD2_UBITS)
 113:                     newmode &= ~((clrval<<6) & set->bits);
 114:                 if (set->cmd2 & CMD2_GBITS)
 115:                     newmode &= ~((clrval<<3) & set->bits);
 116:                 if (set->cmd2 & CMD2_OBITS)
 117:                     newmode &= ~(clrval & set->bits);
 118:             }
 119:             if (set->cmd2 & CMD2_SET) {
 120:                 if (set->cmd2 & CMD2_UBITS)
 121:                     newmode |= (value<<6) & set->bits;
 122:                 if (set->cmd2 & CMD2_GBITS)
 123:                     newmode |= (value<<3) & set->bits;
 124:                 if (set->cmd2 & CMD2_OBITS)
 125:                     newmode |= value & set->bits;
 126:             }
 127:             break;
 128: 
 129:         case '+':
 130:             newmode |= set->bits;
 131:             break;
 132: 
 133:         case '-':
 134:             newmode &= ~set->bits;
 135:             break;
 136: 
 137:         case 'X':
 138:             if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
 139:                 newmode |= set->bits;
 140:             break;
 141: 
 142:         case '\0':
 143:         default:
 144: #ifdef SETMODE_DEBUG
 145:             (void)printf("getmode:%04o -> %04o\n", omode, newmode);
 146: #endif
 147:             return (newmode);
 148:         }
 149: }
 150: 
 151: #define ADDCMD(a, b, c, d)                      \
 152:     if (set >= endset) {                        \
 153:         register BITCMD *newset;                \
 154:         setlen += SET_LEN_INCR;                 \
 155:         newset = (BITCMD *)realloc(saveset, sizeof(BITCMD) * setlen); \
 156:         if (!saveset)                       \
 157:             return ((void *)NULL);              \
 158:         set = newset + (set - saveset);             \
 159:         saveset = newset;                   \
 160:         endset = newset + (setlen - 2);             \
 161:     }                               \
 162:     set = addcmd(set, (a), (b), (c), (d))
 163: 
 164: #define STANDARD_BITS   (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
 165: 
 166: void *
 167: setmode(p)
 168:     register char *p;
 169: {
 170:     register int perm, who;
 171:     char op;
 172:     BITCMD *set, *saveset, *endset;
 173: #ifdef  notnow
 174:     sigset_t sigset, sigoset;
 175: #endif
 176:     mode_t mask;
 177:     int equalopdone, permXbits, setlen;
 178: 
 179:     if (!*p)
 180:         return ((void *)NULL);
 181: 
 182: #ifdef  notnow
 183:     /*
 184: 	 * Get a copy of the mask for the permissions that are mask relative.
 185: 	 * Flip the bits, we want what's not set.  Since it's possible that
 186: 	 * the caller is opening files inside a signal handler, protect them
 187: 	 * as best we can.
 188: 	 */
 189:     sigfillset(&sigset);
 190:         (void)sigprocmask(SIG_BLOCK, &sigset, &sigoset);
 191: #endif
 192:     (void)umask(mask = umask(0));
 193:     mask = ~mask;
 194: #ifdef  notnow
 195:         (void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
 196: #endif
 197: 
 198:     setlen = SET_LEN + 2;
 199: 
 200:     if ((set = (BITCMD *)malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
 201:         return ((void *)NULL);
 202:     saveset = set;
 203:     endset = set + (setlen - 2);
 204: 
 205:     /*
 206: 	 * If an absolute number, get it and return; disallow non-octal digits
 207: 	 * or illegal bits.
 208: 	 */
 209:     if (isdigit(*p)) {
 210:         perm = (mode_t)strtol(p, NULL, 8);
 211:         if (perm & ~(STANDARD_BITS|S_ISVTX)) {
 212:             free(saveset);
 213:             return ((void *)NULL);
 214:         }
 215:         while (*++p)
 216:             if (*p < '0' || *p > '7') {
 217:                 free(saveset);
 218:                 return ((void *)NULL);
 219:             }
 220:         ADDCMD('=', (STANDARD_BITS|S_ISVTX), perm, mask);
 221:         return ((void *)saveset);
 222:     }
 223: 
 224:     /*
 225: 	 * Build list of structures to set/clear/copy bits as described by
 226: 	 * each clause of the symbolic mode.
 227: 	 */
 228:     for (;;) {
 229:         /* First, find out which bits might be modified. */
 230:         for (who = 0;; ++p) {
 231:             switch (*p) {
 232:             case 'a':
 233:                 who |= STANDARD_BITS;
 234:                 break;
 235:             case 'u':
 236:                 who |= S_ISUID|S_IRWXU;
 237:                 break;
 238:             case 'g':
 239:                 who |= S_ISGID|S_IRWXG;
 240:                 break;
 241:             case 'o':
 242:                 who |= S_IRWXO;
 243:                 break;
 244:             default:
 245:                 goto getop;
 246:             }
 247:         }
 248: 
 249: getop:      if ((op = *p++) != '+' && op != '-' && op != '=') {
 250:             free(saveset);
 251:             return ((void *)NULL);
 252:         }
 253:         if (op == '=')
 254:             equalopdone = 0;
 255: 
 256:         who &= ~S_ISVTX;
 257:         for (perm = 0, permXbits = 0;; ++p) {
 258:             switch (*p) {
 259:             case 'r':
 260:                 perm |= S_IRUSR|S_IRGRP|S_IROTH;
 261:                 break;
 262:             case 's':
 263:                 /* If only "other" bits ignore set-id. */
 264:                 if (who & ~S_IRWXO)
 265:                     perm |= S_ISUID|S_ISGID;
 266:                 break;
 267:             case 't':
 268:                 /* If only "other" bits ignore sticky. */
 269:                 if (who & ~S_IRWXO) {
 270:                     who |= S_ISVTX;
 271:                     perm |= S_ISVTX;
 272:                 }
 273:                 break;
 274:             case 'w':
 275:                 perm |= S_IWUSR|S_IWGRP|S_IWOTH;
 276:                 break;
 277:             case 'X':
 278:                 permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
 279:                 break;
 280:             case 'x':
 281:                 perm |= S_IXUSR|S_IXGRP|S_IXOTH;
 282:                 break;
 283:             case 'u':
 284:             case 'g':
 285:             case 'o':
 286:                 /*
 287: 				 * When ever we hit 'u', 'g', or 'o', we have
 288: 				 * to flush out any partial mode that we have,
 289: 				 * and then do the copying of the mode bits.
 290: 				 */
 291:                 if (perm) {
 292:                     ADDCMD(op, who, perm, mask);
 293:                     perm = 0;
 294:                 }
 295:                 if (op == '=')
 296:                     equalopdone = 1;
 297:                 if (op == '+' && permXbits) {
 298:                     ADDCMD('X', who, permXbits, mask);
 299:                     permXbits = 0;
 300:                 }
 301:                 ADDCMD(*p, who, op, mask);
 302:                 break;
 303: 
 304:             default:
 305:                 /*
 306: 				 * Add any permissions that we haven't already
 307: 				 * done.
 308: 				 */
 309:                 if (perm || (op == '=' && !equalopdone)) {
 310:                     if (op == '=')
 311:                         equalopdone = 1;
 312:                     ADDCMD(op, who, perm, mask);
 313:                     perm = 0;
 314:                 }
 315:                 if (permXbits) {
 316:                     ADDCMD('X', who, permXbits, mask);
 317:                     permXbits = 0;
 318:                 }
 319:                 goto apply;
 320:             }
 321:         }
 322: 
 323: apply:      if (!*p)
 324:             break;
 325:         if (*p != ',')
 326:             goto getop;
 327:         ++p;
 328:     }
 329:     set->cmd = 0;
 330: #ifdef SETMODE_DEBUG
 331:     (void)printf("Before compress_mode()\n");
 332:     dumpmode(saveset);
 333: #endif
 334:     compress_mode(saveset);
 335: #ifdef SETMODE_DEBUG
 336:     (void)printf("After compress_mode()\n");
 337:     dumpmode(saveset);
 338: #endif
 339:     return ((void *)saveset);
 340: }
 341: 
 342: static BITCMD *
 343: addcmd(set, op, who, oparg, mask)
 344:     BITCMD *set;
 345:     register int oparg, who;
 346:     register int op;
 347:     u_int mask;
 348: {
 349:     switch (op) {
 350:     case '=':
 351:         set->cmd = '-';
 352:         set->bits = who ? who : STANDARD_BITS;
 353:         set++;
 354: 
 355:         op = '+';
 356:         /* FALLTHROUGH */
 357:     case '+':
 358:     case '-':
 359:     case 'X':
 360:         set->cmd = op;
 361:         set->bits = (who ? who : mask) & oparg;
 362:         break;
 363: 
 364:     case 'u':
 365:     case 'g':
 366:     case 'o':
 367:         set->cmd = op;
 368:         if (who) {
 369:             set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
 370:                     ((who & S_IRGRP) ? CMD2_GBITS : 0) |
 371:                     ((who & S_IROTH) ? CMD2_OBITS : 0);
 372:             set->bits = ~0;
 373:         } else {
 374:             set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
 375:             set->bits = mask;
 376:         }
 377: 
 378:         if (oparg == '+')
 379:             set->cmd2 |= CMD2_SET;
 380:         else if (oparg == '-')
 381:             set->cmd2 |= CMD2_CLR;
 382:         else if (oparg == '=')
 383:             set->cmd2 |= CMD2_SET|CMD2_CLR;
 384:         break;
 385:     }
 386:     return (set + 1);
 387: }
 388: 
 389: #ifdef SETMODE_DEBUG
 390: static void
 391: dumpmode(set)
 392:     register BITCMD *set;
 393: {
 394:     for (; set->cmd; ++set)
 395:         (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
 396:             set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
 397:             set->cmd2 & CMD2_CLR ? " CLR" : "",
 398:             set->cmd2 & CMD2_SET ? " SET" : "",
 399:             set->cmd2 & CMD2_UBITS ? " UBITS" : "",
 400:             set->cmd2 & CMD2_GBITS ? " GBITS" : "",
 401:             set->cmd2 & CMD2_OBITS ? " OBITS" : "");
 402: }
 403: #endif
 404: 
 405: /*
 406:  * Given an array of bitcmd structures, compress by compacting consecutive
 407:  * '+', '-' and 'X' commands into at most 3 commands, one of each.  The 'u',
 408:  * 'g' and 'o' commands continue to be separate.  They could probably be
 409:  * compacted, but it's not worth the effort.
 410:  */
 411: static int
 412: compress_mode(set)
 413:     register BITCMD *set;
 414: {
 415:     register BITCMD *nset;
 416:     register int setbits, clrbits, Xbits, op;
 417: 
 418:     for (nset = set;;) {
 419:         /* Copy over any 'u', 'g' and 'o' commands. */
 420:         while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
 421:             *set++ = *nset++;
 422:             if (!op)
 423:                 return;
 424:         }
 425: 
 426:         for (setbits = clrbits = Xbits = 0;; nset++) {
 427:             if ((op = nset->cmd) == '-') {
 428:                 clrbits |= nset->bits;
 429:                 setbits &= ~nset->bits;
 430:                 Xbits &= ~nset->bits;
 431:             } else if (op == '+') {
 432:                 setbits |= nset->bits;
 433:                 clrbits &= ~nset->bits;
 434:                 Xbits &= ~nset->bits;
 435:             } else if (op == 'X')
 436:                 Xbits |= nset->bits & ~setbits;
 437:             else
 438:                 break;
 439:         }
 440:         if (clrbits) {
 441:             set->cmd = '-';
 442:             set->cmd2 = 0;
 443:             set->bits = clrbits;
 444:             set++;
 445:         }
 446:         if (setbits) {
 447:             set->cmd = '+';
 448:             set->cmd2 = 0;
 449:             set->bits = setbits;
 450:             set++;
 451:         }
 452:         if (Xbits) {
 453:             set->cmd = 'X';
 454:             set->cmd2 = 0;
 455:             set->bits = Xbits;
 456:             set++;
 457:         }
 458:     }
 459: }

Defined functions

addcmd defined in line 342; used 2 times
compress_mode defined in line 411; used 2 times
dumpmode defined in line 390; used 3 times
getmode defined in line 81; used 1 times

Defined variables

sccsid defined in line 38; never used

Defined struct's

bitcmd defined in line 57; never used

Defined typedef's

BITCMD defined in line 61; used 14 times

Defined macros

ADDCMD defined in line 151; used 6 times
CMD2_CLR defined in line 63; used 4 times
CMD2_GBITS defined in line 65; used 5 times
CMD2_OBITS defined in line 66; used 5 times
CMD2_SET defined in line 64; used 5 times
CMD2_UBITS defined in line 67; used 5 times
SET_LEN defined in line 54; used 1 times
SET_LEN_INCR defined in line 55; used 1 times
STANDARD_BITS defined in line 164; used 4 times
Last modified: 1996-02-20
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3709
Valid CSS Valid XHTML 1.0 Strict