Imported Upstream version 2.2.51
[platform/upstream/acl.git] / libacl / __acl_to_any_text.c
1 /*
2   File: __acl_to_any_text.c
3
4   Copyright (C) 1999, 2000
5   Andreas Gruenbacher, <a.gruenbacher@bestbits.at>
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 <stdio.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <pwd.h>
26 #include <grp.h>
27 #include <acl/libacl.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 = 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 = 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                         strncpy(text_p, tabs+x, size);
251                         ADVANCE(TABS-x);
252
253                         strncpy(text_p, EFFECTIVE_STR, size);
254                         ADVANCE(sizeof(EFFECTIVE_STR)-1);
255
256                         switch ((size >= 3) ? 3 : size) {
257                                 case 3:
258                                         text_p[2] = (effective &
259                                                      ACL_EXECUTE) ? 'x' : '-'; 
260                                         /* fall through */
261                                 case 2:
262                                         text_p[1] = (effective &
263                                                      ACL_WRITE) ? 'w' : '-'; 
264                                         /* fall through */
265                                 case 1:
266                                         text_p[0] = (effective &
267                                                      ACL_READ) ? 'r' : '-'; 
268                                         break;
269                         }
270                         ADVANCE(3);
271
272                 }
273         }
274
275         /* zero-terminate string (but don't count '\0' character) */
276         if (size > 0)
277                 *text_p = '\0';
278         
279         return (text_p - orig_text_p);  /* total size required, excluding
280                                            final NULL character. */
281 }
282
283 #undef ADVANCE
284
285
286
287 /*
288   This function is equivalent to the proposed changes to snprintf:
289     snprintf(text_p, size, "%u", i)
290   (The current snprintf returns -1 if the buffer is too small; the proposal
291    is to return the number of characters that would be required. See the
292    snprintf manual page.)
293 */
294
295 static ssize_t
296 snprint_uint(char *text_p, ssize_t size, unsigned int i)
297 {
298         unsigned int tmp = i;
299         int digits = 1;
300         unsigned int factor = 1;
301
302         while ((tmp /= 10) != 0) {
303                 digits++;
304                 factor *= 10;
305         }
306         if (size && (i == 0)) {
307                 *text_p++ = '0';
308         } else {
309                 while (size > 0 && factor > 0) {
310                         *text_p++ = '0' + (i / factor);
311                         size--;
312                         i %= factor;
313                         factor /= 10;
314                 }
315         }
316         if (size)
317                 *text_p = '\0';
318
319         return digits;
320 }
321
322
323 static const char *
324 user_name(uid_t uid)
325 {
326         struct passwd *passwd = getpwuid(uid);
327
328         if (passwd != NULL)
329                 return passwd->pw_name;
330         else
331                 return NULL;
332 }
333
334
335 static const char *
336 group_name(gid_t gid)
337 {
338         struct group *group = getgrgid(gid);
339
340         if (group != NULL)
341                 return group->gr_name;
342         else
343                 return NULL;
344 }
345