139978Sbostic /* 239978Sbostic * Copyright (c) 1989 The Regents of the University of California. 339978Sbostic * All rights reserved. 439978Sbostic * 539978Sbostic * Redistribution and use in source and binary forms are permitted 639978Sbostic * provided that the above copyright notice and this paragraph are 739978Sbostic * duplicated in all such forms and that any documentation, 839978Sbostic * advertising materials, and other materials related to such 939978Sbostic * distribution and use acknowledge that the software was developed 1039978Sbostic * by the University of California, Berkeley. The name of the 1139978Sbostic * University may not be used to endorse or promote products derived 1239978Sbostic * from this software without specific prior written permission. 1339978Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1439978Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1539978Sbostic * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1639978Sbostic */ 1739978Sbostic 1839978Sbostic #if defined(LIBC_SCCS) && !defined(lint) 19*41579Sbostic static char sccsid[] = "@(#)setmode.c 5.2 (Berkeley) 05/10/90"; 2039978Sbostic #endif /* LIBC_SCCS and not lint */ 2139978Sbostic 2239978Sbostic #include <sys/types.h> 2339978Sbostic #include <sys/stat.h> 24*41579Sbostic #include <errno.h> 25*41579Sbostic #include <stdio.h> 2639978Sbostic 27*41579Sbostic #define setbits set[0] 28*41579Sbostic #define clrbits set[1] 29*41579Sbostic #define Xbits set[2] 3039978Sbostic 3139978Sbostic mode_t 32*41579Sbostic getmode(set, omode) 33*41579Sbostic mode_t *set, omode; 3439978Sbostic { 3539978Sbostic register mode_t newmode; 3639978Sbostic 3739978Sbostic newmode = omode & clrbits; 3839978Sbostic newmode |= setbits; 3939978Sbostic if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH)) 4039978Sbostic newmode |= Xbits; 4139978Sbostic return(newmode); 4239978Sbostic } 4339978Sbostic 4439978Sbostic #define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) 4539978Sbostic #define CLR(a) { clrbits |= a; setbits &= ~(a); Xbits &= ~(a); } 4639978Sbostic 47*41579Sbostic mode_t * 4839978Sbostic setmode(p) 4939978Sbostic register char *p; 5039978Sbostic { 51*41579Sbostic extern int errno; 5239978Sbostic register int perm, who; 5339978Sbostic register char op; 54*41579Sbostic mode_t mask, *set; 5539978Sbostic int permXbits; 56*41579Sbostic char *malloc(); 5739978Sbostic 5839978Sbostic /* 5939978Sbostic * get a copy of the mask for the permissions that are mask 6039978Sbostic * relative. Flip the bits, we want what's not set. 6139978Sbostic */ 6239978Sbostic (void)umask(mask = umask(0)); 6339978Sbostic mask = ~mask; 6439978Sbostic 65*41579Sbostic if (!(set = (mode_t *)malloc((u_int)(sizeof(mode_t) * 3)))) { 66*41579Sbostic errno = ENOMEM; 67*41579Sbostic return(NULL); 68*41579Sbostic } 69*41579Sbostic 7039978Sbostic setbits = clrbits = Xbits = 0; 7139978Sbostic 7239978Sbostic /* 7339978Sbostic * if an absolute number, get it and return; disallow non-octal 7439978Sbostic * digits or illegal bits. 7539978Sbostic */ 7639978Sbostic if (isdigit(*p)) { 7739978Sbostic setbits = (mode_t)strtol(p, (char **)0, 8); 7839978Sbostic clrbits = ~(STANDARD_BITS|S_ISTXT); 7939978Sbostic Xbits = 0; 8039978Sbostic while (*++p) 8139978Sbostic if (*p < '0' || *p > '7') 82*41579Sbostic return(NULL); 8339978Sbostic if (setbits & clrbits) 84*41579Sbostic return(NULL); 85*41579Sbostic return(set); 8639978Sbostic } 8739978Sbostic 8839978Sbostic if (!*p) 89*41579Sbostic return(NULL); 9039978Sbostic /* 9139978Sbostic * accumulate bits to add and subtract from each clause of 9239978Sbostic * the symbolic mode 9339978Sbostic */ 9439978Sbostic for (;;) { 9539978Sbostic for (who = 0;; ++p) 9639978Sbostic switch (*p) { 9739978Sbostic case 'a': 9839978Sbostic who |= STANDARD_BITS; 9939978Sbostic break; 10039978Sbostic case 'u': 10139978Sbostic who |= S_ISUID|S_IRWXU; 10239978Sbostic break; 10339978Sbostic case 'g': 10439978Sbostic who |= S_ISGID|S_IRWXG; 10539978Sbostic break; 10639978Sbostic case 'o': 10739978Sbostic who |= S_IRWXO; 10839978Sbostic break; 10939978Sbostic default: 11039978Sbostic goto getop; 11139978Sbostic } 11239978Sbostic 11339978Sbostic getop: if ((op = *p++) != '+' && op != '-' && op != '=') 114*41579Sbostic return(NULL); 11539978Sbostic 11639978Sbostic who &= ~S_ISTXT; 11739978Sbostic for (perm = 0;; ++p) 11839978Sbostic switch (*p) { 11939978Sbostic case 'r': 12039978Sbostic perm |= S_IRUSR|S_IRGRP|S_IROTH; 12139978Sbostic break; 12239978Sbostic case 's': 12339978Sbostic /* if only "other" bits ignore set-id */ 12439978Sbostic if (who & ~S_IRWXO) 12539978Sbostic perm |= S_ISUID|S_ISGID; 12639978Sbostic break; 12739978Sbostic case 't': 12839978Sbostic /* if only "other" bits ignore sticky */ 12939978Sbostic if (who & ~S_IRWXO) { 13039978Sbostic who |= S_ISTXT; 13139978Sbostic perm |= S_ISTXT; 13239978Sbostic } 13339978Sbostic break; 13439978Sbostic case 'w': 13539978Sbostic perm |= S_IWUSR|S_IWGRP|S_IWOTH; 13639978Sbostic break; 13739978Sbostic case 'X': 13839978Sbostic permXbits = S_IXUSR|S_IXGRP|S_IXOTH; 13939978Sbostic break; 14039978Sbostic case 'x': 14139978Sbostic perm |= S_IXUSR|S_IXGRP|S_IXOTH; 14239978Sbostic break; 14339978Sbostic default: 14439978Sbostic goto apply; 14539978Sbostic } 14639978Sbostic 14739978Sbostic apply: switch(op) { 14839978Sbostic case '+': 14939978Sbostic /* 15039978Sbostic * If no perm value, skip. If no who value, use umask 15139978Sbostic * bits. Don't bother clearing any bits, getmode 15239978Sbostic * clears first, then sets. 15339978Sbostic */ 15439978Sbostic if (perm || permXbits) { 15539978Sbostic if (!who) 15639978Sbostic who = mask; 15739978Sbostic if (permXbits) 15839978Sbostic Xbits |= who & permXbits; 15939978Sbostic setbits |= who & perm; 16039978Sbostic } 16139978Sbostic break; 16239978Sbostic case '-': 16339978Sbostic /* 16439978Sbostic * If no perm value, skip. If no who value, use 16539978Sbostic * owner, group, and other. 16639978Sbostic */ 16739978Sbostic if (perm) { 16839978Sbostic if (!who) 16939978Sbostic who = S_IRWXU|S_IRWXG|S_IRWXO; 17039978Sbostic CLR(who & perm); 17139978Sbostic } 17239978Sbostic break; 17339978Sbostic case '=': 17439978Sbostic /* 17539978Sbostic * If no who value, clear all the bits. Otherwise, 17639978Sbostic * clear the bits specified by who. 17739978Sbostic */ 17839978Sbostic if (!who) { 17939978Sbostic CLR(STANDARD_BITS); 18039978Sbostic who = mask; 18139978Sbostic } else 18239978Sbostic CLR(who); 18339978Sbostic if (perm) 18439978Sbostic setbits |= who & perm; 18539978Sbostic break; 18639978Sbostic } 18739978Sbostic 18839978Sbostic if (!*p) 18939978Sbostic break; 19039978Sbostic if (*p != ',') 19139978Sbostic goto getop; 19239978Sbostic ++p; 19339978Sbostic } 19439978Sbostic clrbits = ~clrbits; 195*41579Sbostic return(set); 19639978Sbostic } 197