| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/stat.h> |
| #include <unistd.h> |
| |
| #include "../util.h" |
| |
| mode_t |
| getumask(void) |
| { |
| mode_t mask = umask(0); |
| umask(mask); |
| return mask; |
| } |
| |
| mode_t |
| parsemode(const char *str, mode_t mode, mode_t mask) |
| { |
| char *end; |
| const char *p = str; |
| int octal, op; |
| mode_t who, perm, clear; |
| |
| octal = strtol(str, &end, 8); |
| if (*end == '\0') { |
| if (octal < 0 || octal > 07777) { |
| eprintf("%s: invalid mode\n", str); |
| return -1; |
| } |
| mode = 0; |
| if (octal & 04000) mode |= S_ISUID; |
| if (octal & 02000) mode |= S_ISGID; |
| if (octal & 01000) mode |= S_ISVTX; |
| if (octal & 00400) mode |= S_IRUSR; |
| if (octal & 00200) mode |= S_IWUSR; |
| if (octal & 00100) mode |= S_IXUSR; |
| if (octal & 00040) mode |= S_IRGRP; |
| if (octal & 00020) mode |= S_IWGRP; |
| if (octal & 00010) mode |= S_IXGRP; |
| if (octal & 00004) mode |= S_IROTH; |
| if (octal & 00002) mode |= S_IWOTH; |
| if (octal & 00001) mode |= S_IXOTH; |
| return mode; |
| } |
| next: |
| /* first, determine which bits we will be modifying */ |
| for (who = 0; *p; p++) { |
| switch (*p) { |
| /* masks */ |
| case 'u': |
| who |= S_IRWXU|S_ISUID; |
| continue; |
| case 'g': |
| who |= S_IRWXG|S_ISGID; |
| continue; |
| case 'o': |
| who |= S_IRWXO; |
| continue; |
| case 'a': |
| who |= S_IRWXU|S_ISUID|S_IRWXG|S_ISGID|S_IRWXO; |
| continue; |
| } |
| break; |
| } |
| if (who) { |
| clear = who; |
| } else { |
| clear = S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO; |
| who = ~mask; |
| } |
| while (*p) { |
| switch (*p) { |
| /* opers */ |
| case '=': |
| case '+': |
| case '-': |
| op = (int)*p; |
| break; |
| default: |
| eprintf("%s: invalid mode\n", str); |
| return -1; |
| } |
| |
| perm = 0; |
| switch (*++p) { |
| /* copy */ |
| case 'u': |
| if (mode & S_IRUSR) |
| perm |= S_IRUSR|S_IRGRP|S_IROTH; |
| if (mode & S_IWUSR) |
| perm |= S_IWUSR|S_IWGRP|S_IWOTH; |
| if (mode & S_IXUSR) |
| perm |= S_IXUSR|S_IXGRP|S_IXOTH; |
| if (mode & S_ISUID) |
| perm |= S_ISUID|S_ISGID; |
| p++; |
| break; |
| case 'g': |
| if (mode & S_IRGRP) |
| perm |= S_IRUSR|S_IRGRP|S_IROTH; |
| if (mode & S_IWGRP) |
| perm |= S_IWUSR|S_IWGRP|S_IWOTH; |
| if (mode & S_IXGRP) |
| perm |= S_IXUSR|S_IXGRP|S_IXOTH; |
| if (mode & S_ISGID) |
| perm |= S_ISUID|S_ISGID; |
| p++; |
| break; |
| case 'o': |
| if (mode & S_IROTH) |
| perm |= S_IRUSR|S_IRGRP|S_IROTH; |
| if (mode & S_IWOTH) |
| perm |= S_IWUSR|S_IWGRP|S_IWOTH; |
| if (mode & S_IXOTH) |
| perm |= S_IXUSR|S_IXGRP|S_IXOTH; |
| p++; |
| break; |
| default: |
| for (; *p; p++) { |
| switch (*p) { |
| /* modes */ |
| case 'r': |
| perm |= S_IRUSR|S_IRGRP|S_IROTH; |
| break; |
| case 'w': |
| perm |= S_IWUSR|S_IWGRP|S_IWOTH; |
| break; |
| case 'x': |
| perm |= S_IXUSR|S_IXGRP|S_IXOTH; |
| break; |
| case 's': |
| perm |= S_ISUID|S_ISGID; |
| break; |
| case 't': |
| perm |= S_ISVTX; |
| break; |
| default: |
| goto apply; |
| } |
| } |
| } |
| |
| apply: |
| /* apply */ |
| switch (op) { |
| case '=': |
| mode &= ~clear; |
| /* fallthrough */ |
| case '+': |
| mode |= perm & who; |
| break; |
| case '-': |
| mode &= ~(perm & who); |
| break; |
| } |
| /* if we hit a comma, move on to the next clause */ |
| if (*p == ',') { |
| p++; |
| goto next; |
| } |
| } |
| return mode; |
| } |