Apply ASLR to attr
[platform/upstream/attr.git] / libattr / libattr.c
1 /*
2  * Copyright (c) 2001-2003,2005 Silicon Graphics, Inc.
3  * All Rights Reserved.
4  *
5  * This program is free software: you can redistribute it and/or modify it
6  * under the terms of the GNU Lesser General Public License as published
7  * by the Free Software Foundation, either version 2.1 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include <errno.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <sys/types.h>
24
25 #include <attr/xattr.h>
26 #include <attr/attributes.h>
27
28 #undef MAXNAMELEN
29 #define MAXNAMELEN 256
30 #undef MAXLISTLEN
31 #define MAXLISTLEN 65536
32
33 #undef roundup
34 #define roundup(x,y) ((((x)+((y)-1))/(y))*(y))
35
36 static const char *user_name = "user.";
37 static const char *secure_name = "security.";
38 static const char *trusted_name = "trusted.";
39 static const char *xfsroot_name = "xfsroot.";
40
41 /*
42  * Convert IRIX API components into Linux/XFS API components,
43  * and vice-versa.
44  */
45 static int
46 api_convert(char *name, const char *irixname, int irixflags, int compat)
47 {
48         if (strlen(irixname) >= MAXNAMELEN) {
49                 errno = EINVAL;
50                 return -1;
51         }
52         if (irixflags & ATTR_ROOT) {
53                 if (compat)
54                         strcpy(name, xfsroot_name);
55                 else
56                         strcpy(name, trusted_name);
57         } else if (irixflags & ATTR_SECURE) {
58                 strcpy(name, secure_name);
59         } else {
60                 strcpy(name, user_name);
61         }
62         strcat(name, irixname);
63         return 0;
64 }
65
66 static int
67 api_unconvert(char *name, const char *linuxname, int irixflags)
68 {
69         int type, length;
70
71         length = strlen(user_name);
72         if (strncmp(linuxname, user_name, length) == 0) {
73                 type = 0; /*ATTR_USER*/
74                 goto found;
75         }
76         length = strlen(secure_name);
77         if (strncmp(linuxname, secure_name, length) == 0) {
78                 type = ATTR_SECURE;
79                 goto found;
80         }
81         length = strlen(trusted_name);
82         if (strncmp(linuxname, trusted_name, length) == 0) {
83                 type = ATTR_ROOT;
84                 goto found;
85         }
86         length = strlen(xfsroot_name);
87         if (strncmp(linuxname, xfsroot_name, length) == 0) {
88                 type = ATTR_ROOT;
89                 goto found;
90         }
91         return 1;
92
93 found:
94         if ((irixflags & ATTR_SECURE) != 0 && (type != ATTR_SECURE))
95                 return 1;
96         if ((irixflags & ATTR_ROOT) != 0 && (type != ATTR_ROOT))
97                 return 1;
98         strcpy(name, linuxname + length);
99         return 0;
100 }
101
102
103 int
104 attr_get(const char *path, const char *attrname, char *attrvalue,
105          int *valuelength, int flags)
106 {
107         int c, compat;
108         char name[MAXNAMELEN+16];
109
110         for (compat = 0; compat < 2; compat++) {
111                 if ((c = api_convert(name, attrname, flags, compat)) < 0)
112                         return c;
113                 if (flags & ATTR_DONTFOLLOW)
114                         c = lgetxattr(path, name, attrvalue, *valuelength);
115                 else
116                         c =  getxattr(path, name, attrvalue, *valuelength);
117                 if (c < 0 && (errno == ENOATTR || errno == ENOTSUP))
118                         continue;
119                 break;
120         }
121         if (c < 0)
122                 return c;
123         *valuelength = c;
124         return 0;
125 }
126
127 int
128 attr_getf(int fd, const char *attrname, char *attrvalue,
129           int *valuelength, int flags)
130 {
131         int c, compat;
132         char name[MAXNAMELEN+16];
133
134         for (compat = 0; compat < 2; compat++) {
135                 if ((c = api_convert(name, attrname, flags, compat)) < 0)
136                         return c;
137                 c = fgetxattr(fd, name, attrvalue, *valuelength);
138                 if (c < 0 && (errno == ENOATTR || errno == ENOTSUP))
139                         continue;
140                 break;
141         }
142         if (c < 0)
143                 return c;
144         *valuelength = c;
145         return 0;
146 }
147
148 int
149 attr_set(const char *path, const char *attrname, const char *attrvalue,
150          const int valuelength, int flags)
151 {
152         int c, compat, lflags = 0;
153         char name[MAXNAMELEN+16];
154         void *buffer = (void *)attrvalue;
155
156         if (flags & ATTR_CREATE)
157                 lflags = XATTR_CREATE;
158         else if (flags & ATTR_REPLACE)
159                 lflags = XATTR_REPLACE;
160
161         for (compat = 0; compat < 2; compat++) {
162                 if ((c = api_convert(name, attrname, flags, compat)) < 0)
163                         return c;
164                 if (flags & ATTR_DONTFOLLOW)
165                         c = lsetxattr(path, name, buffer, valuelength, lflags);
166                 else
167                         c = setxattr(path, name, buffer, valuelength, lflags);
168                 if (c < 0 && (errno == ENOATTR || errno == ENOTSUP))
169                         continue;
170                 break;
171         }
172         return c;
173 }
174
175 int
176 attr_setf(int fd, const char *attrname,
177           const char *attrvalue, const int valuelength, int flags)
178 {
179         int c, compat, lflags = 0;
180         char name[MAXNAMELEN+16];
181         void *buffer = (void *)attrvalue;
182
183         if (flags & ATTR_CREATE)
184                 lflags = XATTR_CREATE;
185         else if (flags & ATTR_REPLACE)
186                 lflags = XATTR_REPLACE;
187
188         for (compat = 0; compat < 2; compat++) {
189                 if ((c = api_convert(name, attrname, flags, compat)) < 0)
190                         return c;
191                 c = fsetxattr(fd, name, buffer, valuelength, lflags);
192                 if (c < 0 && (errno == ENOATTR || errno == ENOTSUP))
193                         continue;
194                 break;
195         }
196         return c;
197 }
198
199 int
200 attr_remove(const char *path, const char *attrname, int flags)
201 {
202         int c, compat;
203         char name[MAXNAMELEN+16];
204
205         for (compat = 0; compat < 2; compat++) {
206                 if ((c = api_convert(name, attrname, flags, compat)) < 0)
207                         return c;
208                 if (flags & ATTR_DONTFOLLOW)
209                         c = lremovexattr(path, name);
210                 else
211                         c = removexattr(path, name);
212                 if (c < 0 && (errno == ENOATTR || errno == ENOTSUP))
213                         continue;
214                 break;
215         }
216         return c;
217 }
218
219 int
220 attr_removef(int fd, const char *attrname, int flags)
221 {
222         int c, compat;
223         char name[MAXNAMELEN+16];
224
225         for (compat = 0; compat < 2; compat++) {
226                 if ((c = api_convert(name, attrname, flags, compat)) < 0)
227                         return c;
228                 c = fremovexattr(fd, name);
229                 if (c < 0 && (errno == ENOATTR || errno == ENOTSUP))
230                         continue;
231                 break;
232         }
233         return c;
234 }
235
236
237 /*
238  * Helper routine for attr_list functions.
239  */
240
241 static int
242 attr_list_pack(const char *name, const int valuelen,
243                 char *buffer, const int buffersize,
244                 int *start_offset, int *end_offset)
245 {
246         attrlist_ent_t *aentp;
247         attrlist_t *alist = (attrlist_t *)buffer;
248         int size = roundup(strlen(name) + 1 + sizeof(aentp->a_valuelen), 8);
249
250         if ((*end_offset - size) < (*start_offset + sizeof(alist->al_count))) {
251                 alist->al_more = 1;
252                 return 1;
253         }
254
255         *end_offset -= size;
256         aentp = (attrlist_ent_t *)&buffer[ *end_offset ];
257         aentp->a_valuelen = valuelen;
258         strncpy(aentp->a_name, name, size - sizeof(aentp->a_valuelen));
259
260         *start_offset += sizeof(alist->al_offset);
261         alist->al_offset[alist->al_count] = *end_offset;
262         alist->al_count++;
263         return 0;
264 }
265
266 int
267 attr_list(const char *path, char *buffer, const int buffersize, int flags,
268           attrlist_cursor_t *cursor)
269 {
270         const char *l;
271         int length, vlength, count = 0;
272         char lbuf[MAXLISTLEN];
273         char name[MAXNAMELEN+16];
274         int start_offset, end_offset;
275
276         if (buffersize < sizeof(attrlist_t)) {
277                 errno = EINVAL;
278                 return -1;
279         }
280         bzero(buffer, sizeof(attrlist_t));
281
282         if (flags & ATTR_DONTFOLLOW)
283                 length = llistxattr(path, lbuf, sizeof(lbuf));
284         else
285                 length = listxattr(path, lbuf, sizeof(lbuf));
286         if (length <= 0)
287                 return length;
288
289         start_offset = sizeof(attrlist_t);
290         end_offset = buffersize & ~(8-1);       /* 8 byte align */
291
292         for (l = lbuf; l != lbuf + length; l = strchr(l, '\0') + 1) {
293                 if (api_unconvert(name, l, flags))
294                         continue;
295                 if (flags & ATTR_DONTFOLLOW)
296                         vlength = lgetxattr(path, l, NULL, 0);
297                 else
298                         vlength =  getxattr(path, l, NULL, 0);
299                 if (vlength < 0 && (errno == ENOATTR || errno == ENOTSUP))
300                         continue;
301                 if (count++ < cursor->opaque[0])
302                         continue;
303                 if (attr_list_pack(name, vlength, buffer, buffersize,
304                                    &start_offset, &end_offset)) {
305                         cursor->opaque[0] = count;
306                         break;
307                 }
308         }
309         return 0;
310 }
311
312 int
313 attr_listf(int fd, char *buffer, const int buffersize, int flags,
314            attrlist_cursor_t *cursor)
315 {
316         const char *l;
317         int length, vlength, count = 0;
318         char lbuf[MAXLISTLEN];
319         char name[MAXNAMELEN+16];
320         int start_offset, end_offset;
321
322         if (buffersize < sizeof(attrlist_t)) {
323                 errno = EINVAL;
324                 return -1;
325         }
326         bzero(buffer, sizeof(attrlist_t));
327
328         length = flistxattr(fd, lbuf, sizeof(lbuf));
329         if (length < 0)
330                 return length;
331
332         start_offset = sizeof(attrlist_t);
333         end_offset = buffersize & ~(8-1);       /* 8 byte align */
334
335         for (l = lbuf; l != lbuf + length; l = strchr(l, '\0') + 1) {
336                 if (api_unconvert(name, l, flags))
337                         continue;
338                 vlength = fgetxattr(fd, l, NULL, 0);
339                 if (vlength < 0 && (errno == ENOATTR || errno == ENOTSUP))
340                         continue;
341                 if (count++ < cursor->opaque[0])
342                         continue;
343                 if (attr_list_pack(name, vlength, buffer, buffersize,
344                                    &start_offset, &end_offset)) {
345                         cursor->opaque[0] = count;
346                         break;
347                 }
348         }
349         return 0;
350 }
351
352
353 /*
354  * Helper routines for the attr_multi functions.  In IRIX, the
355  * multi routines are a single syscall - in Linux, we break em
356  * apart in userspace and make individual syscalls for each.
357  */
358
359 static int
360 attr_single(const char *path, attr_multiop_t *op, int flags)
361 {
362         int r = -1;
363
364         errno = -EINVAL;
365         flags |= op->am_flags;
366         if (op->am_opcode & ATTR_OP_GET)
367                 r = attr_get(path, op->am_attrname, op->am_attrvalue,
368                                 &op->am_length, flags);
369         else if (op->am_opcode & ATTR_OP_SET)
370                 r = attr_set(path, op->am_attrname, op->am_attrvalue,
371                                 op->am_length, flags);
372         else if (op->am_opcode & ATTR_OP_REMOVE)
373                 r = attr_remove(path, op->am_attrname, flags);
374         return r;
375 }
376
377 static int
378 attr_singlef(const int fd, attr_multiop_t *op, int flags)
379 {
380         int r = -1;
381
382         errno = -EINVAL;
383         flags |= op->am_flags;
384         if (op->am_opcode & ATTR_OP_GET)
385                 r = attr_getf(fd, op->am_attrname, op->am_attrvalue,
386                                 &op->am_length, flags);
387         else if (op->am_opcode & ATTR_OP_SET)
388                 r = attr_setf(fd, op->am_attrname, op->am_attrvalue,
389                                 op->am_length, flags);
390         else if (op->am_opcode & ATTR_OP_REMOVE)
391                 r = attr_removef(fd, op->am_attrname, flags);
392         return r;
393 }
394
395 /*
396  * Operate on multiple attributes of the same object simultaneously
397  *
398  * From the manpage: "attr_multi will fail if ... a bit other than
399  * ATTR_DONTFOLLOW was set in the flag argument." flags must be
400  * checked here as they are not passed into the kernel.
401  */
402 int
403 attr_multi(const char *path, attr_multiop_t *multiops, int count, int flags)
404 {
405         int i, tmp, r = -1;
406
407         errno = EINVAL;
408         if ((flags & ATTR_DONTFOLLOW) != flags)
409                 return r;
410
411         r = errno = 0;
412         for (i = 0; i < count; i++) {
413                 tmp = attr_single(path, &multiops[i], flags);
414                 if (tmp) r = tmp;
415         }
416         return r;
417 }
418
419 int
420 attr_multif(int fd, attr_multiop_t *multiops, int count, int flags)
421 {
422         int i, tmp, r = -1;
423
424         errno = EINVAL;
425         if ((flags & ATTR_DONTFOLLOW) != flags)
426                 return r;
427
428         r = errno = 0;
429         for (i = 0; i < count; i++) {
430                 tmp = attr_singlef(fd, &multiops[i], flags);
431                 if (tmp) r = tmp;
432         }
433         return r;
434 }