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 const char keyutils_version_string[] = PKGVERSION;
25 const char keyutils_build_string[] = PKGBUILD;
26
27 #ifdef NO_GLIBC_KEYERR
28 static int error_inited;
29 static void (*libc_perror)(const char *msg);
30 static char *(*libc_strerror_r)(int errnum, char *buf, size_t n);
31 //static int (*libc_xpg_strerror_r)(int errnum, char *buf, size_t n);
32 #define RTLD_NEXT ((void *) -1L)
33 #endif
34
35 #define __weak __attribute__((weak))
36
37 key_serial_t __weak add_key(const char *type,
38 const char *description,
39 const void *payload,
40 size_t plen,
41 key_serial_t ringid)
42 {
43 return syscall(__NR_add_key,
44 type, description, payload, plen, ringid);
45 }
46
47 key_serial_t __weak request_key(const char *type,
48 const char *description,
49 const char * callout_info,
50 key_serial_t destringid)
51 {
52 return syscall(__NR_request_key,
53 type, description, callout_info, destringid);
54 }
55
56 static inline long __keyctl(int cmd,
57 unsigned long arg2,
58 unsigned long arg3,
59 unsigned long arg4,
60 unsigned long arg5)
61 {
62 return syscall(__NR_keyctl,
63 cmd, arg2, arg3, arg4, arg5);
64 }
65
66 long __weak keyctl(int cmd, ...)
67 {
68 va_list va;
69 unsigned long arg2, arg3, arg4, arg5;
70
71 va_start(va, cmd);
72 arg2 = va_arg(va, unsigned long);
73 arg3 = va_arg(va, unsigned long);
74 arg4 = va_arg(va, unsigned long);
75 arg5 = va_arg(va, unsigned long);
76 va_end(va);
77
78 return __keyctl(cmd, arg2, arg3, arg4, arg5);
79 }
80
81 key_serial_t keyctl_get_keyring_ID(key_serial_t id, int create)
82 {
83 return keyctl(KEYCTL_GET_KEYRING_ID, id, create);
84 }
85
86 key_serial_t keyctl_join_session_keyring(const char *name)
87 {
88 return keyctl(KEYCTL_JOIN_SESSION_KEYRING, name);
89 }
90
91 long keyctl_update(key_serial_t id, const void *payload, size_t plen)
92 {
93 return keyctl(KEYCTL_UPDATE, id, payload, plen);
94 }
95
96 long keyctl_revoke(key_serial_t id)
97 {
98 return keyctl(KEYCTL_REVOKE, id);
99 }
100
101 long keyctl_chown(key_serial_t id, uid_t uid, gid_t gid)
102 {
103 return keyctl(KEYCTL_CHOWN, id, uid, gid);
104 }
105
106 long keyctl_setperm(key_serial_t id, key_perm_t perm)
107 {
108 return keyctl(KEYCTL_SETPERM, id, perm);
109 }
110
(1) Event noescape: |
"keyctl_describe(key_serial_t, char *, size_t)" does not free or save its pointer parameter "buffer". |
111 long keyctl_describe(key_serial_t id, char *buffer, size_t buflen)
112 {
113 return keyctl(KEYCTL_DESCRIBE, id, buffer, buflen);
114 }
115
116 long keyctl_clear(key_serial_t ringid)
117 {
118 return keyctl(KEYCTL_CLEAR, ringid);
119 }
120
121 long keyctl_link(key_serial_t id, key_serial_t ringid)
122 {
123 return keyctl(KEYCTL_LINK, id, ringid);
124 }
125
126 long keyctl_unlink(key_serial_t id, key_serial_t ringid)
127 {
128 return keyctl(KEYCTL_UNLINK, id, ringid);
129 }
130
131 long keyctl_search(key_serial_t ringid,
132 const char *type,
133 const char *description,
134 key_serial_t destringid)
135 {
136 return keyctl(KEYCTL_SEARCH, ringid, type, description, destringid);
137 }
138
139 long keyctl_read(key_serial_t id, char *buffer, size_t buflen)
140 {
141 return keyctl(KEYCTL_READ, id, buffer, buflen);
142 }
143
144 long keyctl_instantiate(key_serial_t id,
145 const void *payload,
146 size_t plen,
147 key_serial_t ringid)
148 {
149 return keyctl(KEYCTL_INSTANTIATE, id, payload, plen, ringid);
150 }
151
152 long keyctl_negate(key_serial_t id, unsigned timeout, key_serial_t ringid)
153 {
154 return keyctl(KEYCTL_NEGATE, id, timeout, ringid);
155 }
156
157 long keyctl_set_reqkey_keyring(int reqkey_defl)
158 {
159 return keyctl(KEYCTL_SET_REQKEY_KEYRING, reqkey_defl);
160 }
161
162 long keyctl_set_timeout(key_serial_t id, unsigned timeout)
163 {
164 return keyctl(KEYCTL_SET_TIMEOUT, id, timeout);
165 }
166
167 long keyctl_assume_authority(key_serial_t id)
168 {
169 return keyctl(KEYCTL_ASSUME_AUTHORITY, id);
170 }
171
172 long keyctl_get_security(key_serial_t id, char *buffer, size_t buflen)
173 {
174 return keyctl(KEYCTL_GET_SECURITY, id, buffer, buflen);
175 }
176
177 long keyctl_session_to_parent(void)
178 {
179 return keyctl(KEYCTL_SESSION_TO_PARENT);
180 }
181
182 long keyctl_reject(key_serial_t id, unsigned timeout, unsigned error,
183 key_serial_t ringid)
184 {
185 long ret = keyctl(KEYCTL_REJECT, id, timeout, error, ringid);
186
187 /* fall back to keyctl_negate() if this op is not supported by this
188 * kernel version */
189 if (ret == -1 && errno == EOPNOTSUPP)
190 return keyctl_negate(id, timeout, ringid);
191 return ret;
192 }
193
194 long keyctl_instantiate_iov(key_serial_t id,
195 const struct iovec *payload_iov,
196 unsigned ioc,
197 key_serial_t ringid)
198 {
199 long ret = keyctl(KEYCTL_INSTANTIATE_IOV, id, payload_iov, ioc, ringid);
200
201 /* fall back to keyctl_instantiate() if this op is not supported by
202 * this kernel version */
203 if (ret == -1 && errno == EOPNOTSUPP) {
204 unsigned loop;
205 size_t bsize = 0, seg;
206 void *buf, *p;
207
208 if (!payload_iov || !ioc)
209 return keyctl_instantiate(id, NULL, 0, ringid);
210 for (loop = 0; loop < ioc; loop++)
211 bsize += payload_iov[loop].iov_len;
212 if (bsize == 0)
213 return keyctl_instantiate(id, NULL, 0, ringid);
214 p = buf = malloc(bsize);
215 if (!buf)
216 return -1;
217 for (loop = 0; loop < ioc; loop++) {
218 seg = payload_iov[loop].iov_len;
219 p = memcpy(p, payload_iov[loop].iov_base, seg) + seg;
220 }
221 ret = keyctl_instantiate(id, buf, bsize, ringid);
222 free(buf);
223 }
224 return ret;
225 }
226
227 long keyctl_invalidate(key_serial_t id)
228 {
229 return keyctl(KEYCTL_INVALIDATE, id);
230 }
231
232 long keyctl_get_persistent(uid_t uid, key_serial_t id)
233 {
234 return keyctl(KEYCTL_GET_PERSISTENT, uid, id);
235 }
236
237 /*****************************************************************************/
238 /*
239 * fetch key description into an allocated buffer
240 * - resulting string is NUL terminated
241 * - returns count not including NUL
242 */
243 int keyctl_describe_alloc(key_serial_t id, char **_buffer)
244 {
245 char *buf;
246 long buflen, ret;
247
248 ret = keyctl_describe(id, NULL, 0);
(1) Event cond_false: |
Condition "ret < 0", taking false branch |
249 if (ret < 0)
(2) Event if_end: |
End of if statement |
250 return -1;
251
252 buflen = ret;
(3) Event alloc_fn: |
Storage is returned from allocation function "malloc(size_t)". |
(4) Event var_assign: |
Assigning: "buf" = storage returned from "malloc(buflen)". |
Also see events: |
[noescape][leaked_storage] |
253 buf = malloc(buflen);
(5) Event cond_false: |
Condition "!buf", taking false branch |
254 if (!buf)
(6) Event if_end: |
End of if statement |
255 return -1;
256
(7) Event cond_true: |
Condition "true", taking true branch |
257 for (;;) {
258 ret = keyctl_describe(id, buf, buflen);
(9) Event cond_true: |
Condition "ret < 0", taking true branch |
259 if (ret < 0)
(10) Event leaked_storage: |
Variable "buf" going out of scope leaks the storage it points to. |
Also see events: |
[alloc_fn][var_assign][noescape] |
260 return -1;
261
262 if (buflen >= ret)
263 break;
264
265 buflen = ret;
266 buf = realloc(buf, buflen);
267 if (!buf)
268 return -1;
269 }
270
271 *_buffer = buf;
272 return buflen - 1;
273
274 } /* end keyctl_describe_alloc() */
275
276 /*****************************************************************************/
277 /*
278 * fetch key contents into an allocated buffer
279 * - resulting buffer has an extra NUL added to the end
280 * - returns count (not including extraneous NUL)
281 */
282 int keyctl_read_alloc(key_serial_t id, void **_buffer)
283 {
284 void *buf;
285 long buflen, ret;
286
287 ret = keyctl_read(id, NULL, 0);
288 if (ret < 0)
289 return -1;
290
291 buflen = ret;
292 buf = malloc(buflen + 1);
293 if (!buf)
294 return -1;
295
296 for (;;) {
297 ret = keyctl_read(id, buf, buflen);
298 if (ret < 0)
299 return -1;
300
301 if (buflen >= ret)
302 break;
303
304 buflen = ret;
305 buf = realloc(buf, buflen + 1);
306 if (!buf)
307 return -1;
308 }
309
310 ((unsigned char *) buf)[buflen] = 0;
311 *_buffer = buf;
312 return buflen;
313
314 } /* end keyctl_read_alloc() */
315
316 /*****************************************************************************/
317 /*
318 * fetch key security label into an allocated buffer
319 * - resulting string is NUL terminated
320 * - returns count not including NUL
321 */
322 int keyctl_get_security_alloc(key_serial_t id, char **_buffer)
323 {
324 char *buf;
325 long buflen, ret;
326
327 ret = keyctl_get_security(id, NULL, 0);
328 if (ret < 0)
329 return -1;
330
331 buflen = ret;
332 buf = malloc(buflen);
333 if (!buf)
334 return -1;
335
336 for (;;) {
337 ret = keyctl_get_security(id, buf, buflen);
338 if (ret < 0)
339 return -1;
340
341 if (buflen >= ret)
342 break;
343
344 buflen = ret;
345 buf = realloc(buf, buflen);
346 if (!buf)
347 return -1;
348 }
349
350 *_buffer = buf;
351 return buflen - 1;
352 }
353
354 /*
355 * Depth-first recursively apply a function over a keyring tree
356 */
357 static int recursive_key_scan_aux(key_serial_t parent, key_serial_t key,
358 int depth, recursive_key_scanner_t func,
359 void *data)
360 {
361 key_serial_t *pk;
362 key_perm_t perm;
363 size_t ringlen;
364 void *ring;
365 char *desc, type[255];
366 int desc_len, uid, gid, ret, n, kcount = 0;
367
368 if (depth > 800)
369 return 0;
370
371 /* read the key description */
372 desc = NULL;
373 desc_len = keyctl_describe_alloc(key, &desc);
374 if (desc_len < 0)
375 goto do_this_key;
376
377 /* parse */
378 type[0] = 0;
379
380 n = sscanf(desc, "%[^;];%d;%d;%x;", type, &uid, &gid, &perm);
381 if (n != 4) {
382 free(desc);
383 desc = NULL;
384 errno = -EINVAL;
385 desc_len = -1;
386 goto do_this_key;
387 }
388
389 /* if it's a keyring then we're going to want to recursively search it
390 * if we can */
391 if (strcmp(type, "keyring") == 0) {
392 /* read the keyring's contents */
393 ret = keyctl_read_alloc(key, &ring);
394 if (ret < 0)
395 goto do_this_key;
396
397 ringlen = ret;
398
399 /* walk the keyring */
400 pk = ring;
401 for (ringlen = ret;
402 ringlen >= sizeof(key_serial_t);
403 ringlen -= sizeof(key_serial_t)
404 )
405 kcount += recursive_key_scan_aux(key, *pk++, depth + 1,
406 func, data);
407
408 free(ring);
409 }
410
411 do_this_key:
412 kcount += func(parent, key, desc, desc_len, data);
413 free(desc);
414 return kcount;
415 }
416
417 /*
418 * Depth-first apply a function over a keyring tree
419 */
420 int recursive_key_scan(key_serial_t key, recursive_key_scanner_t func, void *data)
421 {
422 return recursive_key_scan_aux(0, key, 0, func, data);
423 }
424
425 /*
426 * Depth-first apply a function over session keyring tree
427 */
428 int recursive_session_key_scan(recursive_key_scanner_t func, void *data)
429 {
430 key_serial_t session =
431 keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 0);
432 if (session > 0)
433 return recursive_key_scan(session, func, data);
434 return 0;
435 }
436
437 /*
438 * Find a key by type and description
439 */
440 key_serial_t find_key_by_type_and_desc(const char *type, const char *desc,
441 key_serial_t destringid)
442 {
443 key_serial_t id, error;
444 FILE *f;
445 char buf[1024], typebuf[40], rdesc[1024], *kdesc, *cp;
446 int n, ndesc, dlen;
447
448 error = ENOKEY;
449
450 id = request_key(type, desc, NULL, destringid);
451 if (id >= 0 || errno == ENOMEM)
452 return id;
453 if (errno != ENOKEY)
454 error = errno;
455
456 dlen = strlen(desc);
457
458 f = fopen("/proc/keys", "r");
459 if (!f) {
460 fprintf(stderr, "libkeyutils: Can't open /proc/keys: %m\n");
461 return -1;
462 }
463
464 while (fgets(buf, sizeof(buf), f)) {
465 cp = strchr(buf, '\n');
466 if (*cp)
467 *cp = '\0';
468
469 n = sscanf(buf, "%x %*s %*u %*s %*x %*d %*d %s %n",
470 &id, typebuf, &ndesc);
471 if (n == 2) {
472 if (strcmp(typebuf, type) != 0)
473 continue;
474 kdesc = buf + ndesc;
475 if (memcmp(kdesc, desc, dlen) != 0)
476 continue;
477 if (kdesc[dlen] != ':' &&
478 kdesc[dlen] != '\0' &&
479 kdesc[dlen] != ' ')
480 continue;
481 kdesc[dlen] = '\0';
482
483 /* The key type appends extra stuff to the end of the
484 * description after a colon in /proc/keys. Colons,
485 * however, are allowed in descriptions, so we need to
486 * make a further check. */
487 n = keyctl_describe(id, rdesc, sizeof(rdesc) - 1);
488 if (n == -1) {
489 if (errno != ENOKEY)
490 error = errno;
491 if (errno == ENOMEM)
492 break;
493 }
494 if (n >= sizeof(rdesc) - 1)
495 continue;
496 rdesc[n] = '\0';
497
498 cp = strrchr(rdesc, ';');
499 if (!cp)
500 continue;
501 cp++;
502 if (strcmp(cp, desc) != 0)
503 continue;
504
505 fclose(f);
506
507 if (destringid &&
508 keyctl_link(id, destringid) == -1)
509 return -1;
510
511 return id;
512 }
513 }
514
515 fclose(f);
516 errno = error;
517 return -1;
518 }
519
520 #ifdef NO_GLIBC_KEYERR
521 /*****************************************************************************/
522 /*
523 * initialise error handling
524 */
525 static void error_init(void)
526 {
527 char *err;
528
529 error_inited = 1;
530
531 dlerror();
532
533 libc_perror = dlsym(RTLD_NEXT,"perror");
534 if (!libc_perror) {
535 fprintf(stderr, "Failed to look up next perror\n");
536 err = dlerror();
537 if (err)
538 fprintf(stderr, "%s\n", err);
539 abort();
540 }
541
542 //fprintf(stderr, "next perror at %p\n", libc_perror);
543
544 libc_strerror_r = dlsym(RTLD_NEXT,"strerror_r");
545 if (!libc_strerror_r) {
546 fprintf(stderr, "Failed to look up next strerror_r\n");
547 err = dlerror();
548 if (err)
549 fprintf(stderr, "%s\n", err);
550 abort();
551 }
552
553 //fprintf(stderr, "next strerror_r at %p\n", libc_strerror_r);
554
555 #if 0
556 libc_xpg_strerror_r = dlsym(RTLD_NEXT,"xpg_strerror_r");
557 if (!libc_xpg_strerror_r) {
558 fprintf(stderr, "Failed to look up next xpg_strerror_r\n");
559 err = dlerror();
560 if (err)
561 fprintf(stderr, "%s\n", err);
562 abort();
563 }
564
565 //fprintf(stderr, "next xpg_strerror_r at %p\n", libc_xpg_strerror_r);
566 #endif
567
568 } /* end error_init() */
569
570 /*****************************************************************************/
571 /*
572 * overload glibc's strerror_r() with a version that knows about key errors
573 */
574 char *strerror_r(int errnum, char *buf, size_t n)
575 {
576 const char *errstr;
577 int len;
578
579 printf("hello\n");
580
581 if (!error_inited)
582 error_init();
583
584 switch (errnum) {
585 case ENOKEY:
586 errstr = "Requested key not available";
587 break;
588
589 case EKEYEXPIRED:
590 errstr = "Key has expired";
591 break;
592
593 case EKEYREVOKED:
594 errstr = "Key has been revoked";
595 break;
596
597 case EKEYREJECTED:
598 errstr = "Key was rejected by service";
599 break;
600
601 default:
602 return libc_strerror_r(errnum, buf, n);
603 }
604
605 len = strlen(errstr) + 1;
606 if (n > len) {
607 errno = ERANGE;
608 if (n > 0) {
609 memcpy(buf, errstr, n - 1);
610 buf[n - 1] = 0;
611 }
612 return NULL;
613 }
614 else {
615 memcpy(buf, errstr, len);
616 return buf;
617 }
618
619 } /* end strerror_r() */
620
621 #if 0
622 /*****************************************************************************/
623 /*
624 * overload glibc's strerror_r() with a version that knows about key errors
625 */
626 int xpg_strerror_r(int errnum, char *buf, size_t n)
627 {
628 const char *errstr;
629 int len;
630
631 if (!error_inited)
632 error_init();
633
634 switch (errnum) {
635 case ENOKEY:
636 errstr = "Requested key not available";
637 break;
638
639 case EKEYEXPIRED:
640 errstr = "Key has expired";
641 break;
642
643 case EKEYREVOKED:
644 errstr = "Key has been revoked";
645 break;
646
647 case EKEYREJECTED:
648 errstr = "Key was rejected by service";
649 break;
650
651 default:
652 return libc_xpg_strerror_r(errnum, buf, n);
653 }
654
655 len = strlen(errstr) + 1;
656 if (n > len) {
657 errno = ERANGE;
658 if (n > 0) {
659 memcpy(buf, errstr, n - 1);
660 buf[n - 1] = 0;
661 }
662 return -1;
663 }
664 else {
665 memcpy(buf, errstr, len);
666 return 0;
667 }
668
669 } /* end xpg_strerror_r() */
670 #endif
671
672 /*****************************************************************************/
673 /*
674 *
675 */
676 void perror(const char *msg)
677 {
678 if (!error_inited)
679 error_init();
680
681 switch (errno) {
682 case ENOKEY:
683 fprintf(stderr, "%s: Requested key not available\n", msg);
684 return;
685
686 case EKEYEXPIRED:
687 fprintf(stderr, "%s: Key has expired\n", msg);
688 return;
689
690 case EKEYREVOKED:
691 fprintf(stderr, "%s: Key has been revoked\n", msg);
692 return;
693
694 case EKEYREJECTED:
695 fprintf(stderr, "%s: Key was rejected by service\n", msg);
696 return;
697
698 default:
699 libc_perror(msg);
700 return;
701 }
702
703 } /* end perror() */
704 #endif
705