Add PIE compilation flags
[platform/upstream/keyutils.git] / keyutils.c
1 /* keyutils.c: key utility library
2  *
3  * Copyright (C) 2005,2011 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, or (at your option) any later version.
10  */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stdint.h>
15 #include <stdarg.h>
16 #include <string.h>
17 #include <unistd.h>
18 #include <dlfcn.h>
19 #include <sys/uio.h>
20 #include <errno.h>
21 #include <asm/unistd.h>
22 #include "keyutils.h"
23
24 #ifdef NO_GLIBC_KEYERR
25 static int error_inited;
26 static void (*libc_perror)(const char *msg);
27 static char *(*libc_strerror_r)(int errnum, char *buf, size_t n);
28 //static int (*libc_xpg_strerror_r)(int errnum, char *buf, size_t n);
29 #define RTLD_NEXT      ((void *) -1L)
30 #endif
31
32 #define __weak __attribute__((weak))
33
34 key_serial_t __weak add_key(const char *type,
35                             const char *description,
36                             const void *payload,
37                             size_t plen,
38                             key_serial_t ringid)
39 {
40         return syscall(__NR_add_key,
41                        type, description, payload, plen, ringid);
42 }
43
44 key_serial_t __weak request_key(const char *type,
45                                 const char *description,
46                                 const char * callout_info,
47                                 key_serial_t destringid)
48 {
49         return syscall(__NR_request_key,
50                        type, description, callout_info, destringid);
51 }
52
53 static inline long __keyctl(int cmd,
54                             unsigned long arg2,
55                             unsigned long arg3,
56                             unsigned long arg4,
57                             unsigned long arg5)
58 {
59         return syscall(__NR_keyctl,
60                        cmd, arg2, arg3, arg4, arg5);
61 }
62
63 long __weak keyctl(int cmd, ...)
64 {
65         va_list va;
66         unsigned long arg2, arg3, arg4, arg5;
67
68         va_start(va, cmd);
69         arg2 = va_arg(va, unsigned long);
70         arg3 = va_arg(va, unsigned long);
71         arg4 = va_arg(va, unsigned long);
72         arg5 = va_arg(va, unsigned long);
73         va_end(va);
74
75         return __keyctl(cmd, arg2, arg3, arg4, arg5);
76 }
77
78 key_serial_t keyctl_get_keyring_ID(key_serial_t id, int create)
79 {
80         return keyctl(KEYCTL_GET_KEYRING_ID, id, create);
81 }
82
83 key_serial_t keyctl_join_session_keyring(const char *name)
84 {
85         return keyctl(KEYCTL_JOIN_SESSION_KEYRING, name);
86 }
87
88 long keyctl_update(key_serial_t id, const void *payload, size_t plen)
89 {
90         return keyctl(KEYCTL_UPDATE, id, payload, plen);
91 }
92
93 long keyctl_revoke(key_serial_t id)
94 {
95         return keyctl(KEYCTL_REVOKE, id);
96 }
97
98 long keyctl_chown(key_serial_t id, uid_t uid, gid_t gid)
99 {
100         return keyctl(KEYCTL_CHOWN, id, uid, gid);
101 }
102
103 long keyctl_setperm(key_serial_t id, key_perm_t perm)
104 {
105         return keyctl(KEYCTL_SETPERM, id, perm);
106 }
107
108 long keyctl_describe(key_serial_t id, char *buffer, size_t buflen)
109 {
110         return keyctl(KEYCTL_DESCRIBE, id, buffer, buflen);
111 }
112
113 long keyctl_clear(key_serial_t ringid)
114 {
115         return keyctl(KEYCTL_CLEAR, ringid);
116 }
117
118 long keyctl_link(key_serial_t id, key_serial_t ringid)
119 {
120         return keyctl(KEYCTL_LINK, id, ringid);
121 }
122
123 long keyctl_unlink(key_serial_t id, key_serial_t ringid)
124 {
125         return keyctl(KEYCTL_UNLINK, id, ringid);
126 }
127
128 long keyctl_search(key_serial_t ringid,
129                    const char *type,
130                    const char *description,
131                    key_serial_t destringid)
132 {
133         return keyctl(KEYCTL_SEARCH, ringid, type, description, destringid);
134 }
135
136 long keyctl_read(key_serial_t id, char *buffer, size_t buflen)
137 {
138         return keyctl(KEYCTL_READ, id, buffer, buflen);
139 }
140
141 long keyctl_instantiate(key_serial_t id,
142                         const void *payload,
143                         size_t plen,
144                         key_serial_t ringid)
145 {
146         return keyctl(KEYCTL_INSTANTIATE, id, payload, plen, ringid);
147 }
148
149 long keyctl_negate(key_serial_t id, unsigned timeout, key_serial_t ringid)
150 {
151         return keyctl(KEYCTL_NEGATE, id, timeout, ringid);
152 }
153
154 long keyctl_set_reqkey_keyring(int reqkey_defl)
155 {
156         return keyctl(KEYCTL_SET_REQKEY_KEYRING, reqkey_defl);
157 }
158
159 long keyctl_set_timeout(key_serial_t id, unsigned timeout)
160 {
161         return keyctl(KEYCTL_SET_TIMEOUT, id, timeout);
162 }
163
164 long keyctl_assume_authority(key_serial_t id)
165 {
166         return keyctl(KEYCTL_ASSUME_AUTHORITY, id);
167 }
168
169 long keyctl_get_security(key_serial_t id, char *buffer, size_t buflen)
170 {
171         return keyctl(KEYCTL_GET_SECURITY, id, buffer, buflen);
172 }
173
174 long keyctl_session_to_parent(void)
175 {
176         return keyctl(KEYCTL_SESSION_TO_PARENT);
177 }
178
179 long keyctl_reject(key_serial_t id, unsigned timeout, unsigned error,
180                    key_serial_t ringid)
181 {
182         long ret = keyctl(KEYCTL_REJECT, id, timeout, error, ringid);
183
184         /* fall back to keyctl_negate() if this op is not supported by this
185          * kernel version */
186         if (ret == -1 && errno == EOPNOTSUPP)
187                 return keyctl_negate(id, timeout, ringid);
188         return ret;
189 }
190
191 long keyctl_instantiate_iov(key_serial_t id,
192                             const struct iovec *payload_iov,
193                             unsigned ioc,
194                             key_serial_t ringid)
195 {
196         long ret = keyctl(KEYCTL_INSTANTIATE_IOV, id, payload_iov, ioc, ringid);
197
198         /* fall back to keyctl_instantiate() if this op is not supported by
199          * this kernel version */
200         if (ret == -1 && errno == EOPNOTSUPP) {
201                 unsigned loop;
202                 size_t bsize = 0, seg;
203                 void *buf, *p;
204
205                 if (!payload_iov || !ioc)
206                         return keyctl_instantiate(id, NULL, 0, ringid);
207                 for (loop = 0; loop < ioc; loop++)
208                         bsize += payload_iov[loop].iov_len;
209                 if (bsize == 0)
210                         return keyctl_instantiate(id, NULL, 0, ringid);
211                 p = buf = malloc(bsize);
212                 if (!buf)
213                         return -1;
214                 for (loop = 0; loop < ioc; loop++) {
215                         seg = payload_iov[loop].iov_len;
216                         p = memcpy(p, payload_iov[loop].iov_base, seg) + seg;
217                 }
218                 ret = keyctl_instantiate(id, buf, bsize, ringid);
219                 free(buf);
220         }
221         return ret;
222 }
223
224 /*****************************************************************************/
225 /*
226  * fetch key description into an allocated buffer
227  * - resulting string is NUL terminated
228  * - returns count not including NUL
229  */
230 int keyctl_describe_alloc(key_serial_t id, char **_buffer)
231 {
232         char *buf;
233         long buflen, ret;
234
235         ret = keyctl_describe(id, NULL, 0);
236         if (ret < 0)
237                 return -1;
238
239         buflen = ret;
240         buf = malloc(buflen);
241         if (!buf)
242                 return -1;
243
244         for (;;) {
245                 ret = keyctl_describe(id, buf, buflen);
246                 if (ret < 0)
247                         return -1;
248
249                 if (buflen >= ret)
250                         break;
251
252                 buflen = ret;
253                 buf = realloc(buf, buflen);
254                 if (!buf)
255                         return -1;
256         }
257
258         *_buffer = buf;
259         return buflen - 1;
260
261 } /* end keyctl_describe_alloc() */
262
263 /*****************************************************************************/
264 /*
265  * fetch key contents into an allocated buffer
266  * - resulting buffer has an extra NUL added to the end
267  * - returns count (not including extraneous NUL)
268  */
269 int keyctl_read_alloc(key_serial_t id, void **_buffer)
270 {
271         void *buf;
272         long buflen, ret;
273
274         ret = keyctl_read(id, NULL, 0);
275         if (ret < 0)
276                 return -1;
277
278         buflen = ret;
279         buf = malloc(buflen + 1);
280         if (!buf)
281                 return -1;
282
283         for (;;) {
284                 ret = keyctl_read(id, buf, buflen);
285                 if (ret < 0)
286                         return -1;
287
288                 if (buflen >= ret)
289                         break;
290
291                 buflen = ret;
292                 buf = realloc(buf, buflen + 1);
293                 if (!buf)
294                         return -1;
295         }
296
297         ((unsigned char *) buf)[buflen] = 0;
298         *_buffer = buf;
299         return buflen;
300
301 } /* end keyctl_read_alloc() */
302
303 /*****************************************************************************/
304 /*
305  * fetch key security label into an allocated buffer
306  * - resulting string is NUL terminated
307  * - returns count not including NUL
308  */
309 int keyctl_get_security_alloc(key_serial_t id, char **_buffer)
310 {
311         char *buf;
312         long buflen, ret;
313
314         ret = keyctl_get_security(id, NULL, 0);
315         if (ret < 0)
316                 return -1;
317
318         buflen = ret;
319         buf = malloc(buflen);
320         if (!buf)
321                 return -1;
322
323         for (;;) {
324                 ret = keyctl_get_security(id, buf, buflen);
325                 if (ret < 0)
326                         return -1;
327
328                 if (buflen >= ret)
329                         break;
330
331                 buflen = ret;
332                 buf = realloc(buf, buflen);
333                 if (!buf)
334                         return -1;
335         }
336
337         *_buffer = buf;
338         return buflen - 1;
339 }
340
341 /*
342  * Depth-first recursively apply a function over a keyring tree
343  */
344 static int recursive_key_scan_aux(key_serial_t parent, key_serial_t key,
345                                   int depth, recursive_key_scanner_t func,
346                                   void *data)
347 {
348         key_serial_t *pk;
349         key_perm_t perm;
350         size_t ringlen;
351         void *ring;
352         char *desc, type[255];
353         int desc_len, uid, gid, ret, n, kcount = 0;
354
355         if (depth > 800)
356                 return 0;
357
358         /* read the key description */
359         desc = NULL;
360         desc_len = keyctl_describe_alloc(key, &desc);
361         if (desc_len < 0)
362                 goto do_this_key;
363
364         /* parse */
365         type[0] = 0;
366
367         n = sscanf(desc, "%[^;];%d;%d;%x;", type, &uid, &gid, &perm);
368         if (n != 4) {
369                 free(desc);
370                 desc = NULL;
371                 errno = -EINVAL;
372                 desc_len = -1;
373                 goto do_this_key;
374         }
375
376         /* if it's a keyring then we're going to want to recursively search it
377          * if we can */
378         if (strcmp(type, "keyring") == 0) {
379                 /* read the keyring's contents */
380                 ret = keyctl_read_alloc(key, &ring);
381                 if (ret < 0)
382                         goto do_this_key;
383
384                 ringlen = ret;
385
386                 /* walk the keyring */
387                 pk = ring;
388                 for (ringlen = ret;
389                      ringlen >= sizeof(key_serial_t);
390                      ringlen -= sizeof(key_serial_t)
391                      )
392                         kcount += recursive_key_scan_aux(key, *pk++, depth + 1,
393                                                          func, data);
394
395                 free(ring);
396         }
397
398 do_this_key:
399         kcount += func(parent, key, desc, desc_len, data);
400         free(desc);
401         return kcount;
402 }
403
404 /*
405  * Depth-first apply a function over a keyring tree
406  */
407 int recursive_key_scan(key_serial_t key, recursive_key_scanner_t func, void *data)
408 {
409         return recursive_key_scan_aux(0, key, 0, func, data);
410 }
411
412 /*
413  * Depth-first apply a function over session keyring tree
414  */
415 int recursive_session_key_scan(recursive_key_scanner_t func, void *data)
416 {
417         key_serial_t session =
418                 keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 0);
419         if (session > 0)
420                 return recursive_key_scan(session, func, data);
421         return 0;
422 }
423
424 #ifdef NO_GLIBC_KEYERR
425 /*****************************************************************************/
426 /*
427  * initialise error handling
428  */
429 static void error_init(void)
430 {
431         char *err;
432
433         error_inited = 1;
434
435         dlerror();
436
437         libc_perror = dlsym(RTLD_NEXT,"perror");
438         if (!libc_perror) {
439                 fprintf(stderr, "Failed to look up next perror\n");
440                 err = dlerror();
441                 if (err)
442                         fprintf(stderr, "%s\n", err);
443                 abort();
444         }
445
446         //fprintf(stderr, "next perror at %p\n", libc_perror);
447
448         libc_strerror_r = dlsym(RTLD_NEXT,"strerror_r");
449         if (!libc_strerror_r) {
450                 fprintf(stderr, "Failed to look up next strerror_r\n");
451                 err = dlerror();
452                 if (err)
453                         fprintf(stderr, "%s\n", err);
454                 abort();
455         }
456
457         //fprintf(stderr, "next strerror_r at %p\n", libc_strerror_r);
458
459 #if 0
460         libc_xpg_strerror_r = dlsym(RTLD_NEXT,"xpg_strerror_r");
461         if (!libc_xpg_strerror_r) {
462                 fprintf(stderr, "Failed to look up next xpg_strerror_r\n");
463                 err = dlerror();
464                 if (err)
465                         fprintf(stderr, "%s\n", err);
466                 abort();
467         }
468
469         //fprintf(stderr, "next xpg_strerror_r at %p\n", libc_xpg_strerror_r);
470 #endif
471
472 } /* end error_init() */
473
474 /*****************************************************************************/
475 /*
476  * overload glibc's strerror_r() with a version that knows about key errors
477  */
478 char *strerror_r(int errnum, char *buf, size_t n)
479 {
480         const char *errstr;
481         int len;
482
483         printf("hello\n");
484
485         if (!error_inited)
486                 error_init();
487
488         switch (errnum) {
489         case ENOKEY:
490                 errstr = "Requested key not available";
491                 break;
492
493         case EKEYEXPIRED:
494                 errstr = "Key has expired";
495                 break;
496
497         case EKEYREVOKED:
498                 errstr = "Key has been revoked";
499                 break;
500
501         case EKEYREJECTED:
502                 errstr = "Key was rejected by service";
503                 break;
504
505         default:
506                 return libc_strerror_r(errnum, buf, n);
507         }
508
509         len = strlen(errstr) + 1;
510         if (n > len) {
511                 errno = ERANGE;
512                 if (n > 0) {
513                         memcpy(buf, errstr, n - 1);
514                         buf[n - 1] = 0;
515                 }
516                 return NULL;
517         }
518         else {
519                 memcpy(buf, errstr, len);
520                 return buf;
521         }
522
523 } /* end strerror_r() */
524
525 #if 0
526 /*****************************************************************************/
527 /*
528  * overload glibc's strerror_r() with a version that knows about key errors
529  */
530 int xpg_strerror_r(int errnum, char *buf, size_t n)
531 {
532         const char *errstr;
533         int len;
534
535         if (!error_inited)
536                 error_init();
537
538         switch (errnum) {
539         case ENOKEY:
540                 errstr = "Requested key not available";
541                 break;
542
543         case EKEYEXPIRED:
544                 errstr = "Key has expired";
545                 break;
546
547         case EKEYREVOKED:
548                 errstr = "Key has been revoked";
549                 break;
550
551         case EKEYREJECTED:
552                 errstr = "Key was rejected by service";
553                 break;
554
555         default:
556                 return libc_xpg_strerror_r(errnum, buf, n);
557         }
558
559         len = strlen(errstr) + 1;
560         if (n > len) {
561                 errno = ERANGE;
562                 if (n > 0) {
563                         memcpy(buf, errstr, n - 1);
564                         buf[n - 1] = 0;
565                 }
566                 return -1;
567         }
568         else {
569                 memcpy(buf, errstr, len);
570                 return 0;
571         }
572
573 } /* end xpg_strerror_r() */
574 #endif
575
576 /*****************************************************************************/
577 /*
578  *
579  */
580 void perror(const char *msg)
581 {
582         if (!error_inited)
583                 error_init();
584
585         switch (errno) {
586         case ENOKEY:
587                 fprintf(stderr, "%s: Requested key not available\n", msg);
588                 return;
589
590         case EKEYEXPIRED:
591                 fprintf(stderr, "%s: Key has expired\n", msg);
592                 return;
593
594         case EKEYREVOKED:
595                 fprintf(stderr, "%s: Key has been revoked\n", msg);
596                 return;
597
598         case EKEYREJECTED:
599                 fprintf(stderr, "%s: Key was rejected by service\n", msg);
600                 return;
601
602         default:
603                 libc_perror(msg);
604                 return;
605         }
606
607 } /* end perror() */
608 #endif