(root)/
acl-2.3.1/
libacl/
acl_from_text.c
       1  /*
       2    File: acl_from_text.c
       3  
       4    Copyright (C) 1999, 2000, 2001
       5    Andreas Gruenbacher, <andreas.gruenbacher@gmail.com>
       6  
       7    This program is free software; you can redistribute it and/or
       8    modify it under the terms of the GNU Lesser General Public
       9    License as published by the Free Software Foundation; either
      10    version 2.1 of the License, or (at your option) any later version.
      11  
      12    This program is distributed in the hope that it will be useful,
      13    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15    Lesser General Public License for more details.
      16  
      17    You should have received a copy of the GNU Lesser General Public
      18    License along with this library; if not, write to the Free Software
      19    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
      20  */
      21  
      22  #include "config.h"
      23  #include <string.h>
      24  #include <pwd.h>
      25  #include <grp.h>
      26  #include "libacl.h"
      27  #include "misc.h"
      28  
      29  
      30  #define SKIP_WS(x) do { \
      31  	while (*(x)==' ' || *(x)=='\t' || *(x)=='\n' || *(x)=='\r') \
      32  		(x)++; \
      33  	if (*(x)=='#') { \
      34  		while (*(x)!='\n' && *(x)!='\0') \
      35  			(x)++; \
      36  	} \
      37  	} while (0)
      38  
      39  
      40  static int parse_acl_entry(const char **text_p, acl_t *acl_p);
      41  
      42  
      43  /* 23.4.13 */
      44  acl_t
      45  acl_from_text(const char *buf_p)
      46  {
      47  	acl_t acl;
      48  	acl = acl_init(0);
      49  	if (!acl)
      50  		return NULL;
      51  	if (!buf_p) {
      52  		errno = EINVAL;
      53  		return NULL;
      54  	}
      55  	while (*buf_p != '\0') {
      56  		if (parse_acl_entry(&buf_p, &acl) != 0)
      57  			goto fail;
      58  		SKIP_WS(buf_p);
      59  		if (*buf_p == ',') {
      60  			buf_p++;
      61  			SKIP_WS(buf_p);
      62  		}
      63  	}
      64  	if (*buf_p != '\0') {
      65  		errno = EINVAL;
      66  		goto fail;
      67  	}
      68  
      69  	return acl;
      70  
      71  fail:
      72  	acl_free(acl);
      73  	return NULL;
      74  }
      75  
      76  
      77  static int
      78  skip_tag_name(const char **text_p, const char *token)
      79  {
      80  	size_t len = strlen(token);
      81  	const char *text = *text_p;
      82  
      83  	SKIP_WS(text);
      84  	if (strncmp(text, token, len) == 0) {
      85  		text += len;
      86  		goto delimiter;
      87  	}
      88  	if (*text == *token) {
      89  		text++;
      90  		goto delimiter;
      91  	}
      92  	return 0;
      93  
      94  delimiter:
      95  	SKIP_WS(text);
      96  	if (*text == ':')
      97  		text++;
      98  	*text_p = text;
      99  	return 1;
     100  }
     101  
     102  
     103  static char *
     104  get_token(const char **text_p)
     105  {
     106  	char *token = NULL;
     107  	const char *ep;
     108  
     109  	ep = *text_p;
     110  	SKIP_WS(ep);
     111  
     112  	while (*ep!='\0' && *ep!='\r' && *ep!='\n' && *ep!=':' && *ep!=',')
     113  		ep++;
     114  	if (ep == *text_p)
     115  		goto after_token;
     116  	token = (char*)malloc(ep - *text_p + 1);
     117  	if (token == 0)
     118  		goto after_token;
     119  	memcpy(token, *text_p, (ep - *text_p));
     120  	token[ep - *text_p] = '\0';
     121  after_token:
     122  	if (*ep == ':')
     123  		ep++;
     124  	*text_p = ep;
     125  	return token;
     126  }
     127  
     128  
     129  static int
     130  get_id(const char *token, id_t *id_p)
     131  {
     132  	char *ep;
     133  	long l;
     134  	l = strtol(token, &ep, 0);
     135  	if (*ep != '\0')
     136  		return -1;
     137  	if (l < 0) {
     138  		/*
     139  		  Negative values are interpreted as 16-bit numbers,
     140  		  so that id -2 maps to 65534 (nobody/nogroup), etc.
     141  		*/
     142  		l &= 0xFFFF;
     143  	}
     144  	*id_p = l;
     145  	return 0;
     146  }
     147  
     148  
     149  static int
     150  get_uid(const char *token, uid_t *uid_p)
     151  {
     152  	struct passwd *passwd;
     153  
     154  	if (get_id(token, uid_p) == 0)
     155  		return 0;
     156  	errno = 0;
     157  	passwd = getpwnam(token);
     158  	if (passwd) {
     159  		*uid_p = passwd->pw_uid;
     160  		return 0;
     161  	}
     162  	if (errno == 0)
     163  		errno = EINVAL;
     164  	return -1;
     165  }
     166  
     167  
     168  static int
     169  get_gid(const char *token, gid_t *gid_p)
     170  {
     171  	struct group *group;
     172  
     173  	if (get_id(token, (uid_t *)gid_p) == 0)
     174  		return 0;
     175  	errno = 0;
     176  	group = getgrnam(token);
     177  	if (group) {
     178  		*gid_p = group->gr_gid;
     179  		return 0;
     180  	}
     181  	if (errno == 0)
     182  		errno = EINVAL;
     183  	return -1;
     184  }
     185  
     186  
     187  /*
     188  	Parses the next acl entry in text_p.
     189  
     190  	Returns:
     191  		-1 on error, 0 on success.
     192  */
     193  
     194  static int
     195  parse_acl_entry(const char **text_p, acl_t *acl_p)
     196  {
     197  	acl_entry_obj entry_obj;
     198  	acl_entry_t entry_d;
     199  	char *str;
     200  	const char *backup;
     201  	int error, perm_chars;
     202  
     203  	new_obj_p_here(acl_entry, &entry_obj);
     204  	init_acl_entry_obj(entry_obj);
     205  
     206  	/* parse acl entry type */
     207  	SKIP_WS(*text_p);
     208  	switch (**text_p) {
     209  		case 'u':  /* user */
     210  			if (!skip_tag_name(text_p, "user"))
     211  				goto fail;
     212  			backup = *text_p;
     213  			str = get_token(text_p);
     214  			if (str) {
     215  				entry_obj.etag = ACL_USER;
     216  				error = get_uid(__acl_unquote(str),
     217  						&entry_obj.eid.qid);
     218  				free(str);
     219  				if (error) {
     220  					*text_p = backup;
     221  					return -1;
     222  				}
     223  			} else {
     224  				entry_obj.etag = ACL_USER_OBJ;
     225  			}
     226  			break;
     227  
     228  		case 'g':  /* group */
     229  			if (!skip_tag_name(text_p, "group"))
     230  				goto fail;
     231  			backup = *text_p;
     232  			str = get_token(text_p);
     233  			if (str) {
     234  				entry_obj.etag = ACL_GROUP;
     235  				error = get_gid(__acl_unquote(str),
     236  						&entry_obj.eid.qid);
     237  				free(str);
     238  				if (error) {
     239  					*text_p = backup;
     240  					return -1;
     241  				}
     242  			} else {
     243  				entry_obj.etag = ACL_GROUP_OBJ;
     244  			}
     245  			break;
     246  
     247  		case 'm':  /* mask */
     248  			if (!skip_tag_name(text_p, "mask"))
     249  				goto fail;
     250  			/* skip empty entry qualifier field (this field may
     251  			   be missing for compatibility with Solaris.) */
     252  			SKIP_WS(*text_p);
     253  			if (**text_p == ':')
     254  				(*text_p)++;
     255  			entry_obj.etag = ACL_MASK;
     256  			break;
     257  
     258  		case 'o':  /* other */
     259  			if (!skip_tag_name(text_p, "other"))
     260  				goto fail;
     261  			/* skip empty entry qualifier field (this field may
     262  			   be missing for compatibility with Solaris.) */
     263  			SKIP_WS(*text_p);
     264  			if (**text_p == ':')
     265  				(*text_p)++;
     266  			entry_obj.etag = ACL_OTHER;
     267  			break;
     268  
     269  		default:
     270  			goto fail;
     271  	}
     272  
     273  	for (perm_chars=0; perm_chars<3; perm_chars++, (*text_p)++) {
     274  		switch(**text_p) {
     275  			case 'r':
     276  				if (entry_obj.eperm.sperm & ACL_READ)
     277  					goto fail;
     278  				entry_obj.eperm.sperm |= ACL_READ;
     279  				break;
     280  
     281  			case 'w':
     282  				if (entry_obj.eperm.sperm  & ACL_WRITE)
     283  					goto fail;
     284  				entry_obj.eperm.sperm  |= ACL_WRITE;
     285  				break;
     286  
     287  			case 'x':
     288  				if (entry_obj.eperm.sperm  & ACL_EXECUTE)
     289  					goto fail;
     290  				entry_obj.eperm.sperm  |= ACL_EXECUTE;
     291  				break;
     292  
     293  			case '-':
     294  				/* ignore */
     295  				break;
     296  
     297  			default:
     298  				if (perm_chars == 0)
     299  					goto fail;
     300  				goto create_entry;
     301  		}
     302  	}
     303  
     304  create_entry:
     305  	if (acl_create_entry(acl_p, &entry_d) != 0)
     306  		return -1;
     307  #pragma GCC diagnostic push
     308  #pragma GCC diagnostic ignored "-Waddress"
     309  	if (acl_copy_entry(entry_d, int2ext(&entry_obj)) != 0)
     310  		return -1;
     311  #pragma GCC diagnostic pop
     312  	return 0;
     313  
     314  fail:
     315  	errno = EINVAL;
     316  	return -1;
     317  }
     318