loadfont,setfont: make them NOEXEC
[oweals/busybox.git] / libbb / parse_mode.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * parse_mode implementation for busybox
4  *
5  * Copyright (C) 2003  Manuel Novoa III  <mjn3@codepoet.org>
6  *
7  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8  */
9
10 /* http://www.opengroup.org/onlinepubs/007904975/utilities/chmod.html */
11
12 #include "libbb.h"
13
14 /* This function is used from NOFORK applets. It must not allocate anything */
15
16 #define FILEMODEBITS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
17
18 int FAST_FUNC bb_parse_mode(const char *s, unsigned current_mode)
19 {
20         static const mode_t who_mask[] = {
21                 S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO, /* a */
22                 S_ISUID | S_IRWXU,           /* u */
23                 S_ISGID | S_IRWXG,           /* g */
24                 S_IRWXO                      /* o */
25         };
26         static const mode_t perm_mask[] = {
27                 S_IRUSR | S_IRGRP | S_IROTH, /* r */
28                 S_IWUSR | S_IWGRP | S_IWOTH, /* w */
29                 S_IXUSR | S_IXGRP | S_IXOTH, /* x */
30                 S_IXUSR | S_IXGRP | S_IXOTH, /* X -- special -- see below */
31                 S_ISUID | S_ISGID,           /* s */
32                 S_ISVTX                      /* t */
33         };
34         static const char who_chars[] ALIGN1 = "augo";
35         static const char perm_chars[] ALIGN1 = "rwxXst";
36
37         const char *p;
38         mode_t wholist;
39         mode_t permlist;
40         mode_t new_mode;
41         char op;
42
43         if ((unsigned char)(*s - '0') < 8) {
44                 unsigned long tmp;
45                 char *e;
46
47                 tmp = strtoul(s, &e, 8);
48                 if (*e || (tmp > 07777U)) { /* Check range and trailing chars. */
49                         return -1;
50                 }
51                 return tmp;
52         }
53
54         new_mode = current_mode;
55
56         /* Note: we allow empty clauses, and hence empty modes.
57          * We treat an empty mode as no change to perms. */
58
59         while (*s) {  /* Process clauses. */
60                 if (*s == ',') {  /* We allow empty clauses. */
61                         ++s;
62                         continue;
63                 }
64
65                 /* Get a wholist. */
66                 wholist = 0;
67  WHO_LIST:
68                 p = who_chars;
69                 do {
70                         if (*p == *s) {
71                                 wholist |= who_mask[(int)(p-who_chars)];
72                                 if (!*++s) {
73                                         return -1;
74                                 }
75                                 goto WHO_LIST;
76                         }
77                 } while (*++p);
78
79                 do {    /* Process action list. */
80                         if ((*s != '+') && (*s != '-')) {
81                                 if (*s != '=') {
82                                         return -1;
83                                 }
84                                 /* Since op is '=', clear all bits corresponding to the
85                                  * wholist, or all file bits if wholist is empty. */
86                                 permlist = ~FILEMODEBITS;
87                                 if (wholist) {
88                                         permlist = ~wholist;
89                                 }
90                                 new_mode &= permlist;
91                         }
92                         op = *s++;
93
94                         /* Check for permcopy. */
95                         p = who_chars + 1;  /* Skip 'a' entry. */
96                         do {
97                                 if (*p == *s) {
98                                         int i = 0;
99                                         permlist = who_mask[(int)(p-who_chars)]
100                                                          & (S_IRWXU | S_IRWXG | S_IRWXO)
101                                                          & new_mode;
102                                         do {
103                                                 if (permlist & perm_mask[i]) {
104                                                         permlist |= perm_mask[i];
105                                                 }
106                                         } while (++i < 3);
107                                         ++s;
108                                         goto GOT_ACTION;
109                                 }
110                         } while (*++p);
111
112                         /* It was not a permcopy, so get a permlist. */
113                         permlist = 0;
114  PERM_LIST:
115                         p = perm_chars;
116                         do {
117                                 if (*p == *s) {
118                                         if ((*p != 'X')
119                                          || (new_mode & (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH))
120                                         ) {
121                                                 permlist |= perm_mask[(int)(p-perm_chars)];
122                                         }
123                                         if (!*++s) {
124                                                 break;
125                                         }
126                                         goto PERM_LIST;
127                                 }
128                         } while (*++p);
129  GOT_ACTION:
130                         if (permlist) { /* The permlist was nonempty. */
131                                 mode_t tmp = wholist;
132                                 if (!wholist) {
133                                         mode_t u_mask = umask(0);
134                                         umask(u_mask);
135                                         tmp = ~u_mask;
136                                 }
137                                 permlist &= tmp;
138                                 if (op == '-') {
139                                         new_mode &= ~permlist;
140                                 } else {
141                                         new_mode |= permlist;
142                                 }
143                         }
144                 } while (*s && (*s != ','));
145         }
146
147         return new_mode;
148 }