1 /* keyutils.c: key utility library
3 * Copyright (C) 2005,2011 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
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.
21 #include <asm/unistd.h>
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)
32 #define __weak __attribute__((weak))
34 key_serial_t __weak add_key(const char *type,
35 const char *description,
40 return syscall(__NR_add_key,
41 type, description, payload, plen, ringid);
44 key_serial_t __weak request_key(const char *type,
45 const char *description,
46 const char * callout_info,
47 key_serial_t destringid)
49 return syscall(__NR_request_key,
50 type, description, callout_info, destringid);
53 static inline long __keyctl(int cmd,
59 return syscall(__NR_keyctl,
60 cmd, arg2, arg3, arg4, arg5);
63 long __weak keyctl(int cmd, ...)
66 unsigned long arg2, arg3, arg4, arg5;
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);
75 return __keyctl(cmd, arg2, arg3, arg4, arg5);
78 key_serial_t keyctl_get_keyring_ID(key_serial_t id, int create)
80 return keyctl(KEYCTL_GET_KEYRING_ID, id, create);
83 key_serial_t keyctl_join_session_keyring(const char *name)
85 return keyctl(KEYCTL_JOIN_SESSION_KEYRING, name);
88 long keyctl_update(key_serial_t id, const void *payload, size_t plen)
90 return keyctl(KEYCTL_UPDATE, id, payload, plen);
93 long keyctl_revoke(key_serial_t id)
95 return keyctl(KEYCTL_REVOKE, id);
98 long keyctl_chown(key_serial_t id, uid_t uid, gid_t gid)
100 return keyctl(KEYCTL_CHOWN, id, uid, gid);
103 long keyctl_setperm(key_serial_t id, key_perm_t perm)
105 return keyctl(KEYCTL_SETPERM, id, perm);
108 long keyctl_describe(key_serial_t id, char *buffer, size_t buflen)
110 return keyctl(KEYCTL_DESCRIBE, id, buffer, buflen);
113 long keyctl_clear(key_serial_t ringid)
115 return keyctl(KEYCTL_CLEAR, ringid);
118 long keyctl_link(key_serial_t id, key_serial_t ringid)
120 return keyctl(KEYCTL_LINK, id, ringid);
123 long keyctl_unlink(key_serial_t id, key_serial_t ringid)
125 return keyctl(KEYCTL_UNLINK, id, ringid);
128 long keyctl_search(key_serial_t ringid,
130 const char *description,
131 key_serial_t destringid)
133 return keyctl(KEYCTL_SEARCH, ringid, type, description, destringid);
136 long keyctl_read(key_serial_t id, char *buffer, size_t buflen)
138 return keyctl(KEYCTL_READ, id, buffer, buflen);
141 long keyctl_instantiate(key_serial_t id,
146 return keyctl(KEYCTL_INSTANTIATE, id, payload, plen, ringid);
149 long keyctl_negate(key_serial_t id, unsigned timeout, key_serial_t ringid)
151 return keyctl(KEYCTL_NEGATE, id, timeout, ringid);
154 long keyctl_set_reqkey_keyring(int reqkey_defl)
156 return keyctl(KEYCTL_SET_REQKEY_KEYRING, reqkey_defl);
159 long keyctl_set_timeout(key_serial_t id, unsigned timeout)
161 return keyctl(KEYCTL_SET_TIMEOUT, id, timeout);
164 long keyctl_assume_authority(key_serial_t id)
166 return keyctl(KEYCTL_ASSUME_AUTHORITY, id);
169 long keyctl_get_security(key_serial_t id, char *buffer, size_t buflen)
171 return keyctl(KEYCTL_GET_SECURITY, id, buffer, buflen);
174 long keyctl_session_to_parent(void)
176 return keyctl(KEYCTL_SESSION_TO_PARENT);
179 long keyctl_reject(key_serial_t id, unsigned timeout, unsigned error,
182 long ret = keyctl(KEYCTL_REJECT, id, timeout, error, ringid);
184 /* fall back to keyctl_negate() if this op is not supported by this
186 if (ret == -1 && errno == EOPNOTSUPP)
187 return keyctl_negate(id, timeout, ringid);
191 long keyctl_instantiate_iov(key_serial_t id,
192 const struct iovec *payload_iov,
196 long ret = keyctl(KEYCTL_INSTANTIATE_IOV, id, payload_iov, ioc, ringid);
198 /* fall back to keyctl_instantiate() if this op is not supported by
199 * this kernel version */
200 if (ret == -1 && errno == EOPNOTSUPP) {
202 size_t bsize = 0, seg;
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;
210 return keyctl_instantiate(id, NULL, 0, ringid);
211 p = buf = malloc(bsize);
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;
218 ret = keyctl_instantiate(id, buf, bsize, ringid);
224 /*****************************************************************************/
226 * fetch key description into an allocated buffer
227 * - resulting string is NUL terminated
228 * - returns count not including NUL
230 int keyctl_describe_alloc(key_serial_t id, char **_buffer)
235 ret = keyctl_describe(id, NULL, 0);
240 buf = malloc(buflen);
245 ret = keyctl_describe(id, buf, buflen);
253 buf = realloc(buf, buflen);
261 } /* end keyctl_describe_alloc() */
263 /*****************************************************************************/
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)
269 int keyctl_read_alloc(key_serial_t id, void **_buffer)
274 ret = keyctl_read(id, NULL, 0);
279 buf = malloc(buflen + 1);
284 ret = keyctl_read(id, buf, buflen);
292 buf = realloc(buf, buflen + 1);
297 ((unsigned char *) buf)[buflen] = 0;
301 } /* end keyctl_read_alloc() */
303 /*****************************************************************************/
305 * fetch key security label into an allocated buffer
306 * - resulting string is NUL terminated
307 * - returns count not including NUL
309 int keyctl_get_security_alloc(key_serial_t id, char **_buffer)
314 ret = keyctl_get_security(id, NULL, 0);
319 buf = malloc(buflen);
324 ret = keyctl_get_security(id, buf, buflen);
332 buf = realloc(buf, buflen);
342 * Depth-first recursively apply a function over a keyring tree
344 static int recursive_key_scan_aux(key_serial_t parent, key_serial_t key,
345 int depth, recursive_key_scanner_t func,
352 char *desc, type[255];
353 int desc_len, uid, gid, ret, n, kcount = 0;
358 /* read the key description */
360 desc_len = keyctl_describe_alloc(key, &desc);
367 n = sscanf(desc, "%[^;];%d;%d;%x;", type, &uid, &gid, &perm);
376 /* if it's a keyring then we're going to want to recursively search it
378 if (strcmp(type, "keyring") == 0) {
379 /* read the keyring's contents */
380 ret = keyctl_read_alloc(key, &ring);
386 /* walk the keyring */
389 ringlen >= sizeof(key_serial_t);
390 ringlen -= sizeof(key_serial_t)
392 kcount += recursive_key_scan_aux(key, *pk++, depth + 1,
399 kcount += func(parent, key, desc, desc_len, data);
405 * Depth-first apply a function over a keyring tree
407 int recursive_key_scan(key_serial_t key, recursive_key_scanner_t func, void *data)
409 return recursive_key_scan_aux(0, key, 0, func, data);
413 * Depth-first apply a function over session keyring tree
415 int recursive_session_key_scan(recursive_key_scanner_t func, void *data)
417 key_serial_t session =
418 keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 0);
420 return recursive_key_scan(session, func, data);
424 #ifdef NO_GLIBC_KEYERR
425 /*****************************************************************************/
427 * initialise error handling
429 static void error_init(void)
437 libc_perror = dlsym(RTLD_NEXT,"perror");
439 fprintf(stderr, "Failed to look up next perror\n");
442 fprintf(stderr, "%s\n", err);
446 //fprintf(stderr, "next perror at %p\n", libc_perror);
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");
453 fprintf(stderr, "%s\n", err);
457 //fprintf(stderr, "next strerror_r at %p\n", libc_strerror_r);
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");
465 fprintf(stderr, "%s\n", err);
469 //fprintf(stderr, "next xpg_strerror_r at %p\n", libc_xpg_strerror_r);
472 } /* end error_init() */
474 /*****************************************************************************/
476 * overload glibc's strerror_r() with a version that knows about key errors
478 char *strerror_r(int errnum, char *buf, size_t n)
490 errstr = "Requested key not available";
494 errstr = "Key has expired";
498 errstr = "Key has been revoked";
502 errstr = "Key was rejected by service";
506 return libc_strerror_r(errnum, buf, n);
509 len = strlen(errstr) + 1;
513 memcpy(buf, errstr, n - 1);
519 memcpy(buf, errstr, len);
523 } /* end strerror_r() */
526 /*****************************************************************************/
528 * overload glibc's strerror_r() with a version that knows about key errors
530 int xpg_strerror_r(int errnum, char *buf, size_t n)
540 errstr = "Requested key not available";
544 errstr = "Key has expired";
548 errstr = "Key has been revoked";
552 errstr = "Key was rejected by service";
556 return libc_xpg_strerror_r(errnum, buf, n);
559 len = strlen(errstr) + 1;
563 memcpy(buf, errstr, n - 1);
569 memcpy(buf, errstr, len);
573 } /* end xpg_strerror_r() */
576 /*****************************************************************************/
580 void perror(const char *msg)
587 fprintf(stderr, "%s: Requested key not available\n", msg);
591 fprintf(stderr, "%s: Key has expired\n", msg);
595 fprintf(stderr, "%s: Key has been revoked\n", msg);
599 fprintf(stderr, "%s: Key was rejected by service\n", msg);