3 (Linux Access Control List Management)
5 Copyright (C) 1999, 2000
6 Andreas Gruenbacher, <a.gruenbacher@bestbits.at>
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 #include <sys/types.h>
39 #define SKIP_WS(x) ({ \
40 while (*(x)==' ' || *(x)=='\t' || *(x)=='\n' || *(x)=='\r') \
50 size_t len = strlen(token);
51 const char *text = *text_p;
54 if (strncmp(text, token, len) == 0) {
58 if (*text == *token) {
70 if (*text == ',' || *text == '\0') {
82 char *token = NULL, *t;
89 while (*ep!='\0' && *ep!='\r' && *ep!='\n' && *ep!=':' && *ep!=',')
93 token = (char*)malloc(ep - bp + 1);
96 memcpy(token, bp, ep - bp);
98 /* Trim trailing whitespace */
99 t = token + (ep - bp - 1);
101 (*t==' ' || *t=='\t' || *t=='\n' || *t=='\r'))
120 l = strtol(token, &ep, 0);
125 Negative values are interpreted as 16-bit numbers,
126 so that id -2 maps to 65534 (nobody/nogroup), etc.
140 struct passwd *passwd;
142 if (get_id(token, (id_t *)uid_p) == 0)
144 passwd = getpwnam(token);
146 *uid_p = passwd->pw_uid;
163 if (get_id(token, (id_t *)gid_p) == 0)
165 group = getgrnam(token);
167 *gid_p = group->gr_gid;
178 Parses the next acl entry in text_p.
181 -1 on error, 0 on success.
190 cmd_t cmd = cmd_init();
193 int error, perm_chars;
197 cmd->c_cmd = seq_cmd;
198 if (parse_mode & SEQ_PROMOTE_ACL)
199 cmd->c_type = ACL_TYPE_DEFAULT;
201 cmd->c_type = ACL_TYPE_ACCESS;
202 cmd->c_id = ACL_UNDEFINED_ID;
205 if (parse_mode & SEQ_PARSE_DEFAULT) {
206 /* check for default acl entry */
208 if (skip_tag_name(text_p, "default")) {
209 if (parse_mode & SEQ_PROMOTE_ACL) {
210 /* if promoting from acl to default acl and
211 a default acl entry is found, fail. */
215 cmd->c_type = ACL_TYPE_DEFAULT;
219 /* parse acl entry type */
222 skip_tag_name(text_p, "user");
226 str = get_token(text_p);
228 cmd->c_tag = ACL_USER;
229 error = get_uid(unquote(str), &cmd->c_id);
236 cmd->c_tag = ACL_USER_OBJ;
240 case 'g': /* group */
241 if (!skip_tag_name(text_p, "group"))
245 str = get_token(text_p);
247 cmd->c_tag = ACL_GROUP;
248 error = get_gid(unquote(str), &cmd->c_id);
255 cmd->c_tag = ACL_GROUP_OBJ;
259 case 'o': /* other */
260 if (!skip_tag_name(text_p, "other"))
262 /* skip empty entry qualifier field (this field may
263 be missing for compatibility with Solaris.) */
267 cmd->c_tag = ACL_OTHER;
271 if (!skip_tag_name(text_p, "mask"))
273 /* skip empty entry qualifier field (this field may
274 be missing for compatibility with Solaris.) */
278 cmd->c_tag = ACL_MASK;
281 default: /* assume "user:" */
286 if (**text_p == ',' || **text_p == '\0') {
287 if (parse_mode & SEQ_PARSE_NO_PERM)
292 if (!(parse_mode & SEQ_PARSE_WITH_PERM))
295 /* parse permissions */
297 if (**text_p >= '0' && **text_p <= '7') {
299 while (**text_p == '0')
301 if (**text_p >= '1' && **text_p <= '7') {
302 cmd->c_perm = (*(*text_p)++ - '0');
308 for (perm_chars=0; perm_chars<3; perm_chars++, (*text_p)++) {
311 if (cmd->c_perm & CMD_PERM_READ)
313 cmd->c_perm |= CMD_PERM_READ;
316 case 'w': /* write */
317 if (cmd->c_perm & CMD_PERM_WRITE)
319 cmd->c_perm |= CMD_PERM_WRITE;
322 case 'x': /* execute */
323 if (cmd->c_perm & CMD_PERM_EXECUTE)
325 cmd->c_perm |= CMD_PERM_EXECUTE;
328 case 'X': /* execute only if directory or some
329 entries already have execute permissions
331 if (cmd->c_perm & CMD_PERM_COND_EXECUTE)
333 cmd->c_perm |= CMD_PERM_COND_EXECUTE;
357 Parse a comma-separated list of acl entries.
359 which is set to the index of the first character that was not parsed,
360 or -1 in case of success.
370 const char *initial_text_p = text_p;
376 while (*text_p != '\0') {
377 cmd = parse_acl_cmd(&text_p, seq_cmd, parse_mode);
382 if (seq_append(seq, cmd) != 0) {
392 if (*text_p != '\0') {
401 *which = (text_p - initial_text_p);
418 Max PATH_MAX bytes even for UTF-8 path names and additional 9
419 bytes for "# file: ". Not a good solution but for now it is the
420 best I can do without too much impact on the code. [tw]
422 char linebuf[(4*PATH_MAX)+9];
425 int comments_read = 0;
430 *uid_p = ACL_UNDEFINED_ID;
432 *gid_p = ACL_UNDEFINED_ID;
440 if (c==' ' || c=='\t' || c=='\r' || c=='\n') {
452 if (fgets(linebuf, sizeof(linebuf), file) == NULL)
457 p = strrchr(linebuf, '\0');
458 while (p > linebuf &&
459 (*(p-1)=='\r' || *(p-1)=='\n')) {
466 if (strncmp(cp, "file:", 5) == 0) {
474 *path_p = (char*)malloc(strlen(cp)+1);
479 } else if (strncmp(cp, "owner:", 6) == 0) {
484 if (*uid_p != ACL_UNDEFINED_ID)
486 if (get_uid(unquote(cp), uid_p) != 0)
489 } else if (strncmp(cp, "group:", 6) == 0) {
494 if (*gid_p != ACL_UNDEFINED_ID)
496 if (get_gid(unquote(cp), gid_p) != 0)
499 } else if (strncmp(cp, "flags:", 6) == 0) {
507 else if (cp[0] != '-')
511 else if (cp[1] != '-')
515 else if (cp[2] != '-')
526 return comments_read;
528 if (path_p && *path_p) {
553 if (fgets(linebuf, sizeof(linebuf), file) == NULL)
561 if (!(parse_mode & SEQ_PARSE_MULTI))
564 } else if (*cp == '#') {
568 cmd = parse_acl_cmd(&cp, seq_cmd, parse_mode);
573 if (seq_append(seq, cmd) != 0) {
579 if (*cp != '\0' && *cp != '#') {
591 *which = (cp - linebuf);