(root)/
acl-2.3.1/
libacl/
__acl_to_any_text.c
       1  /*
       2    File: __acl_to_any_text.c
       3  
       4    Copyright (C) 1999, 2000
       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 <stdio.h>
      24  #include <errno.h>
      25  #include <string.h>
      26  #include <pwd.h>
      27  #include <grp.h>
      28  #include "libacl.h"
      29  #include "misc.h"
      30  
      31  static ssize_t acl_entry_to_any_str(const acl_entry_t entry_d, char *text_p,
      32  				    ssize_t size, const acl_entry_t mask_d,
      33  				    const char *prefix, int options);
      34  static ssize_t snprint_uint(char *text_p, ssize_t size, unsigned int i);
      35  static const char *user_name(uid_t uid);
      36  static const char *group_name(gid_t uid);
      37  
      38  char *
      39  __acl_to_any_text(acl_t acl, ssize_t *len_p, const char *prefix,
      40  		  char separator, const char *suffix, int options)
      41  {
      42  	acl_obj *acl_obj_p = ext2int(acl, acl);
      43  	ssize_t size, len = 0, entry_len = 0,
      44  		suffix_len = suffix ? strlen(suffix) : 0;
      45  	string_obj *string_obj_p, *tmp;
      46  	acl_entry_obj *entry_obj_p, *mask_obj_p = NULL;
      47  	if (!acl_obj_p)
      48  		return NULL;
      49  	size = acl->a_used * 15 + 1;
      50  	string_obj_p = new_var_obj_p(string, size);
      51  	if (!string_obj_p)
      52  		return NULL;
      53  
      54  	if (options & (TEXT_SOME_EFFECTIVE|TEXT_ALL_EFFECTIVE)) {
      55  		/* fetch the ACL_MASK entry */
      56  		FOREACH_ACL_ENTRY(entry_obj_p, acl_obj_p) {
      57  			if (entry_obj_p->etag == ACL_MASK) {
      58  				mask_obj_p = entry_obj_p;
      59  				break;
      60  			}
      61  		}
      62  	}
      63  
      64  	FOREACH_ACL_ENTRY(entry_obj_p, acl_obj_p) {
      65  	repeat:
      66  		entry_len = acl_entry_to_any_str(int2ext(entry_obj_p),
      67  		                                 string_obj_p->sstr + len,
      68  						 size-len,
      69  						 int2ext(mask_obj_p),
      70  						 prefix,
      71  						 options);
      72  		if (entry_len < 0)
      73  			goto fail;
      74  		else if (len + entry_len + suffix_len + 1 > size) {
      75  			while (len + entry_len + suffix_len + 1 > size)
      76  				size <<= 1;
      77  			tmp = realloc_var_obj_p(string, string_obj_p, size);
      78  			if (tmp == NULL)
      79  				goto fail;
      80  			string_obj_p = tmp;
      81  			goto repeat;
      82  		} else
      83  			len += entry_len;
      84  		string_obj_p->sstr[len] = separator;
      85  		len++;
      86  	}
      87  	if (len)
      88  		len--;
      89  	if (len && suffix) {
      90  		strcpy(string_obj_p->sstr + len, suffix);
      91  		len += suffix_len;
      92  	} else
      93  		string_obj_p->sstr[len] = '\0';
      94  
      95  	if (len_p)
      96  		*len_p = len;
      97  	return (char *)int2ext(string_obj_p);
      98  
      99  fail:
     100  	free_obj_p(string_obj_p);
     101  	return NULL;
     102  }
     103  
     104  #define ADVANCE(x) \
     105  	text_p += (x); \
     106  	size -= (x); \
     107  	if (size < 0) \
     108  		size = 0;
     109  
     110  #define ABBREV(s, str_len) \
     111  	if (options & TEXT_ABBREVIATE) { \
     112  		if (size > 0) \
     113  			text_p[0] = *(s); \
     114  		if (size > 1) \
     115  			text_p[1] = ':'; \
     116  		ADVANCE(2); \
     117  	} else { \
     118  		strncpy(text_p, (s), size); \
     119  		ADVANCE(str_len); \
     120  	}
     121  
     122  #define EFFECTIVE_STR		"#effective:"
     123  
     124  static ssize_t
     125  acl_entry_to_any_str(const acl_entry_t entry_d, char *text_p, ssize_t size,
     126  	const acl_entry_t mask_d, const char *prefix, int options)
     127  {
     128  	#define TABS 4
     129  	static const char *tabs = "\t\t\t\t";
     130  	acl_entry_obj *entry_obj_p = ext2int(acl_entry, entry_d);
     131  	acl_entry_obj *mask_obj_p = NULL;
     132  	permset_t effective;
     133  	acl_tag_t type;
     134  	ssize_t x;
     135  	const char *orig_text_p = text_p, *str;
     136  	if (!entry_obj_p)
     137  		return -1;
     138  	if (mask_d) {
     139  		mask_obj_p = ext2int(acl_entry, mask_d);
     140  		if (!mask_obj_p)
     141  			return -1;
     142  	}
     143  	if (text_p == NULL)
     144  		size = 0;
     145  
     146  	if (prefix) {
     147  		strncpy(text_p, prefix, size);
     148  		ADVANCE(strlen(prefix));
     149  	}
     150  
     151  	type = entry_obj_p->etag;
     152  	switch (type) {
     153  		case ACL_USER_OBJ:  /* owner */
     154  			mask_obj_p = NULL;
     155  			/* fall through */
     156  		case ACL_USER:  /* additional user */
     157  			ABBREV("user:", 5);
     158  			if (type == ACL_USER) {
     159  				if (options & TEXT_NUMERIC_IDS)
     160  					str = NULL;
     161  				else
     162  					str = __acl_quote(user_name(
     163  						entry_obj_p->eid.qid), ":, \t\n\r");
     164  				if (str != NULL) {
     165  					strncpy(text_p, str, size);
     166  					ADVANCE(strlen(str));
     167  				} else {
     168  					x = snprint_uint(text_p, size,
     169  					             entry_obj_p->eid.qid);
     170  					ADVANCE(x);
     171  				}
     172  			}
     173  			if (size > 0)
     174  				*text_p = ':';
     175  			ADVANCE(1);
     176  			break;
     177  
     178  		case ACL_GROUP_OBJ:  /* owning group */
     179  		case ACL_GROUP:  /* additional group */
     180  			ABBREV("group:", 6);
     181  			if (type == ACL_GROUP) {
     182  				if (options & TEXT_NUMERIC_IDS)
     183  					str = NULL;
     184  				else
     185  					str = __acl_quote(group_name(
     186  						entry_obj_p->eid.qid), ":, \t\n\r");
     187  				if (str != NULL) {
     188  					strncpy(text_p, str, size);
     189  					ADVANCE(strlen(str));
     190  				} else {
     191  					x = snprint_uint(text_p, size,
     192  					             entry_obj_p->eid.qid);
     193  					ADVANCE(x);
     194  				}
     195  			}
     196  			if (size > 0)
     197  				*text_p = ':';
     198  			ADVANCE(1);
     199  			break;
     200  
     201  		case ACL_MASK:  /* acl mask */
     202  			mask_obj_p = NULL;
     203  			ABBREV("mask:", 5);
     204  			if (size > 0)
     205  				*text_p = ':';
     206  			ADVANCE(1);
     207  			break;
     208  
     209  		case ACL_OTHER:  /* other users */
     210  			mask_obj_p = NULL;
     211  			/* fall through */
     212  			ABBREV("other:", 6);
     213  			if (size > 0)
     214  				*text_p = ':';
     215  			ADVANCE(1);
     216  			break;
     217  
     218  		default:
     219  			return 0;
     220  	}
     221  
     222  	switch ((size >= 3) ? 3 : size) {
     223  		case 3:
     224  			text_p[2] = (entry_obj_p->eperm.sperm &
     225  			             ACL_EXECUTE) ? 'x' : '-'; 
     226  			/* fall through */
     227  		case 2:
     228  			text_p[1] = (entry_obj_p->eperm.sperm &
     229  			             ACL_WRITE) ? 'w' : '-'; 
     230  			/* fall through */
     231  		case 1:
     232  			text_p[0] = (entry_obj_p->eperm.sperm &
     233  			             ACL_READ) ? 'r' : '-'; 
     234  			break;
     235  	}
     236  	ADVANCE(3);
     237  
     238  	if (mask_obj_p &&
     239  	    (options & (TEXT_SOME_EFFECTIVE|TEXT_ALL_EFFECTIVE))) {
     240  		mask_obj_p = ext2int(acl_entry, mask_d);
     241  		if (!mask_obj_p)
     242  			return -1;
     243  
     244  		effective = entry_obj_p->eperm.sperm &
     245  		                 mask_obj_p->eperm.sperm;
     246  		if (effective != entry_obj_p->eperm.sperm ||
     247  		    options & TEXT_ALL_EFFECTIVE) {
     248  			x = (options & TEXT_SMART_INDENT) ?
     249  				((text_p - orig_text_p)/8) : TABS-1;
     250  
     251  			/* use at least one tab for indentation */
     252  			if (x > (TABS-1))
     253  				x = (TABS-1);
     254  
     255  			strncpy(text_p, tabs+x, size);
     256  			ADVANCE(TABS-x);
     257  
     258  			strncpy(text_p, EFFECTIVE_STR, size);
     259  			ADVANCE(sizeof(EFFECTIVE_STR)-1);
     260  
     261  			switch ((size >= 3) ? 3 : size) {
     262  				case 3:
     263  					text_p[2] = (effective &
     264  						     ACL_EXECUTE) ? 'x' : '-'; 
     265  					/* fall through */
     266  				case 2:
     267  					text_p[1] = (effective &
     268  						     ACL_WRITE) ? 'w' : '-'; 
     269  					/* fall through */
     270  				case 1:
     271  					text_p[0] = (effective &
     272  						     ACL_READ) ? 'r' : '-'; 
     273  					break;
     274  			}
     275  			ADVANCE(3);
     276  
     277  		}
     278  	}
     279  
     280  	/* zero-terminate string (but don't count '\0' character) */
     281  	if (size > 0)
     282  		*text_p = '\0';
     283  	
     284  	return (text_p - orig_text_p);  /* total size required, excluding
     285  	                                   final NULL character. */
     286  }
     287  
     288  #undef ADVANCE
     289  
     290  
     291  
     292  /*
     293    This function is equivalent to the proposed changes to snprintf:
     294      snprintf(text_p, size, "%u", i)
     295    (The current snprintf returns -1 if the buffer is too small; the proposal
     296     is to return the number of characters that would be required. See the
     297     snprintf manual page.)
     298  */
     299  
     300  static ssize_t
     301  snprint_uint(char *text_p, ssize_t size, unsigned int i)
     302  {
     303  	unsigned int tmp = i;
     304  	int digits = 1;
     305  	unsigned int factor = 1;
     306  
     307  	while ((tmp /= 10) != 0) {
     308  		digits++;
     309  		factor *= 10;
     310  	}
     311  	if (size && (i == 0)) {
     312  		*text_p++ = '0';
     313  	} else {
     314  		while (size > 0 && factor > 0) {
     315  			*text_p++ = '0' + (i / factor);
     316  			size--;
     317  			i %= factor;
     318  			factor /= 10;
     319  		}
     320  	}
     321  	if (size)
     322  		*text_p = '\0';
     323  
     324  	return digits;
     325  }
     326  
     327  
     328  static const char *
     329  user_name(uid_t uid)
     330  {
     331  	struct passwd *passwd = getpwuid(uid);
     332  
     333  	if (passwd != NULL)
     334  		return passwd->pw_name;
     335  	else
     336  		return NULL;
     337  }
     338  
     339  
     340  static const char *
     341  group_name(gid_t gid)
     342  {
     343  	struct group *group = getgrgid(gid);
     344  
     345  	if (group != NULL)
     346  		return group->gr_name;
     347  	else
     348  		return NULL;
     349  }
     350