diff options
Diffstat (limited to 'keyutils-1.5.6/keyutils.c')
-rw-r--r-- | keyutils-1.5.6/keyutils.c | 616 |
1 files changed, 616 insertions, 0 deletions
diff --git a/keyutils-1.5.6/keyutils.c b/keyutils-1.5.6/keyutils.c new file mode 100644 index 0000000..329bfae --- /dev/null +++ b/keyutils-1.5.6/keyutils.c @@ -0,0 +1,616 @@ +/* keyutils.c: key utility library + * + * Copyright (C) 2005,2011 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdarg.h> +#include <string.h> +#include <unistd.h> +#include <dlfcn.h> +#include <sys/uio.h> +#include <errno.h> +#include <asm/unistd.h> +#include "keyutils.h" + +const char keyutils_version_string[] = PKGVERSION; +const char keyutils_build_string[] = PKGBUILD; + +#ifdef NO_GLIBC_KEYERR +static int error_inited; +static void (*libc_perror)(const char *msg); +static char *(*libc_strerror_r)(int errnum, char *buf, size_t n); +//static int (*libc_xpg_strerror_r)(int errnum, char *buf, size_t n); +#define RTLD_NEXT ((void *) -1L) +#endif + +#define __weak __attribute__((weak)) + +key_serial_t __weak add_key(const char *type, + const char *description, + const void *payload, + size_t plen, + key_serial_t ringid) +{ + return syscall(__NR_add_key, + type, description, payload, plen, ringid); +} + +key_serial_t __weak request_key(const char *type, + const char *description, + const char * callout_info, + key_serial_t destringid) +{ + return syscall(__NR_request_key, + type, description, callout_info, destringid); +} + +static inline long __keyctl(int cmd, + unsigned long arg2, + unsigned long arg3, + unsigned long arg4, + unsigned long arg5) +{ + return syscall(__NR_keyctl, + cmd, arg2, arg3, arg4, arg5); +} + +long __weak keyctl(int cmd, ...) +{ + va_list va; + unsigned long arg2, arg3, arg4, arg5; + + va_start(va, cmd); + arg2 = va_arg(va, unsigned long); + arg3 = va_arg(va, unsigned long); + arg4 = va_arg(va, unsigned long); + arg5 = va_arg(va, unsigned long); + va_end(va); + + return __keyctl(cmd, arg2, arg3, arg4, arg5); +} + +key_serial_t keyctl_get_keyring_ID(key_serial_t id, int create) +{ + return keyctl(KEYCTL_GET_KEYRING_ID, id, create); +} + +key_serial_t keyctl_join_session_keyring(const char *name) +{ + return keyctl(KEYCTL_JOIN_SESSION_KEYRING, name); +} + +long keyctl_update(key_serial_t id, const void *payload, size_t plen) +{ + return keyctl(KEYCTL_UPDATE, id, payload, plen); +} + +long keyctl_revoke(key_serial_t id) +{ + return keyctl(KEYCTL_REVOKE, id); +} + +long keyctl_chown(key_serial_t id, uid_t uid, gid_t gid) +{ + return keyctl(KEYCTL_CHOWN, id, uid, gid); +} + +long keyctl_setperm(key_serial_t id, key_perm_t perm) +{ + return keyctl(KEYCTL_SETPERM, id, perm); +} + +long keyctl_describe(key_serial_t id, char *buffer, size_t buflen) +{ + return keyctl(KEYCTL_DESCRIBE, id, buffer, buflen); +} + +long keyctl_clear(key_serial_t ringid) +{ + return keyctl(KEYCTL_CLEAR, ringid); +} + +long keyctl_link(key_serial_t id, key_serial_t ringid) +{ + return keyctl(KEYCTL_LINK, id, ringid); +} + +long keyctl_unlink(key_serial_t id, key_serial_t ringid) +{ + return keyctl(KEYCTL_UNLINK, id, ringid); +} + +long keyctl_search(key_serial_t ringid, + const char *type, + const char *description, + key_serial_t destringid) +{ + return keyctl(KEYCTL_SEARCH, ringid, type, description, destringid); +} + +long keyctl_read(key_serial_t id, char *buffer, size_t buflen) +{ + return keyctl(KEYCTL_READ, id, buffer, buflen); +} + +long keyctl_instantiate(key_serial_t id, + const void *payload, + size_t plen, + key_serial_t ringid) +{ + return keyctl(KEYCTL_INSTANTIATE, id, payload, plen, ringid); +} + +long keyctl_negate(key_serial_t id, unsigned timeout, key_serial_t ringid) +{ + return keyctl(KEYCTL_NEGATE, id, timeout, ringid); +} + +long keyctl_set_reqkey_keyring(int reqkey_defl) +{ + return keyctl(KEYCTL_SET_REQKEY_KEYRING, reqkey_defl); +} + +long keyctl_set_timeout(key_serial_t id, unsigned timeout) +{ + return keyctl(KEYCTL_SET_TIMEOUT, id, timeout); +} + +long keyctl_assume_authority(key_serial_t id) +{ + return keyctl(KEYCTL_ASSUME_AUTHORITY, id); +} + +long keyctl_get_security(key_serial_t id, char *buffer, size_t buflen) +{ + return keyctl(KEYCTL_GET_SECURITY, id, buffer, buflen); +} + +long keyctl_session_to_parent(void) +{ + return keyctl(KEYCTL_SESSION_TO_PARENT); +} + +long keyctl_reject(key_serial_t id, unsigned timeout, unsigned error, + key_serial_t ringid) +{ + long ret = keyctl(KEYCTL_REJECT, id, timeout, error, ringid); + + /* fall back to keyctl_negate() if this op is not supported by this + * kernel version */ + if (ret == -1 && errno == EOPNOTSUPP) + return keyctl_negate(id, timeout, ringid); + return ret; +} + +long keyctl_instantiate_iov(key_serial_t id, + const struct iovec *payload_iov, + unsigned ioc, + key_serial_t ringid) +{ + long ret = keyctl(KEYCTL_INSTANTIATE_IOV, id, payload_iov, ioc, ringid); + + /* fall back to keyctl_instantiate() if this op is not supported by + * this kernel version */ + if (ret == -1 && errno == EOPNOTSUPP) { + unsigned loop; + size_t bsize = 0, seg; + void *buf, *p; + + if (!payload_iov || !ioc) + return keyctl_instantiate(id, NULL, 0, ringid); + for (loop = 0; loop < ioc; loop++) + bsize += payload_iov[loop].iov_len; + if (bsize == 0) + return keyctl_instantiate(id, NULL, 0, ringid); + p = buf = malloc(bsize); + if (!buf) + return -1; + for (loop = 0; loop < ioc; loop++) { + seg = payload_iov[loop].iov_len; + p = memcpy(p, payload_iov[loop].iov_base, seg) + seg; + } + ret = keyctl_instantiate(id, buf, bsize, ringid); + free(buf); + } + return ret; +} + +long keyctl_invalidate(key_serial_t id) +{ + return keyctl(KEYCTL_INVALIDATE, id); +} + +/*****************************************************************************/ +/* + * fetch key description into an allocated buffer + * - resulting string is NUL terminated + * - returns count not including NUL + */ +int keyctl_describe_alloc(key_serial_t id, char **_buffer) +{ + char *buf; + long buflen, ret; + + ret = keyctl_describe(id, NULL, 0); + if (ret < 0) + return -1; + + buflen = ret; + buf = malloc(buflen); + if (!buf) + return -1; + + for (;;) { + ret = keyctl_describe(id, buf, buflen); + if (ret < 0) + return -1; + + if (buflen >= ret) + break; + + buflen = ret; + buf = realloc(buf, buflen); + if (!buf) + return -1; + } + + *_buffer = buf; + return buflen - 1; + +} /* end keyctl_describe_alloc() */ + +/*****************************************************************************/ +/* + * fetch key contents into an allocated buffer + * - resulting buffer has an extra NUL added to the end + * - returns count (not including extraneous NUL) + */ +int keyctl_read_alloc(key_serial_t id, void **_buffer) +{ + void *buf; + long buflen, ret; + + ret = keyctl_read(id, NULL, 0); + if (ret < 0) + return -1; + + buflen = ret; + buf = malloc(buflen + 1); + if (!buf) + return -1; + + for (;;) { + ret = keyctl_read(id, buf, buflen); + if (ret < 0) + return -1; + + if (buflen >= ret) + break; + + buflen = ret; + buf = realloc(buf, buflen + 1); + if (!buf) + return -1; + } + + ((unsigned char *) buf)[buflen] = 0; + *_buffer = buf; + return buflen; + +} /* end keyctl_read_alloc() */ + +/*****************************************************************************/ +/* + * fetch key security label into an allocated buffer + * - resulting string is NUL terminated + * - returns count not including NUL + */ +int keyctl_get_security_alloc(key_serial_t id, char **_buffer) +{ + char *buf; + long buflen, ret; + + ret = keyctl_get_security(id, NULL, 0); + if (ret < 0) + return -1; + + buflen = ret; + buf = malloc(buflen); + if (!buf) + return -1; + + for (;;) { + ret = keyctl_get_security(id, buf, buflen); + if (ret < 0) + return -1; + + if (buflen >= ret) + break; + + buflen = ret; + buf = realloc(buf, buflen); + if (!buf) + return -1; + } + + *_buffer = buf; + return buflen - 1; +} + +/* + * Depth-first recursively apply a function over a keyring tree + */ +static int recursive_key_scan_aux(key_serial_t parent, key_serial_t key, + int depth, recursive_key_scanner_t func, + void *data) +{ + key_serial_t *pk; + key_perm_t perm; + size_t ringlen; + void *ring; + char *desc, type[255]; + int desc_len, uid, gid, ret, n, kcount = 0; + + if (depth > 800) + return 0; + + /* read the key description */ + desc = NULL; + desc_len = keyctl_describe_alloc(key, &desc); + if (desc_len < 0) + goto do_this_key; + + /* parse */ + type[0] = 0; + + n = sscanf(desc, "%[^;];%d;%d;%x;", type, &uid, &gid, &perm); + if (n != 4) { + free(desc); + desc = NULL; + errno = -EINVAL; + desc_len = -1; + goto do_this_key; + } + + /* if it's a keyring then we're going to want to recursively search it + * if we can */ + if (strcmp(type, "keyring") == 0) { + /* read the keyring's contents */ + ret = keyctl_read_alloc(key, &ring); + if (ret < 0) + goto do_this_key; + + ringlen = ret; + + /* walk the keyring */ + pk = ring; + for (ringlen = ret; + ringlen >= sizeof(key_serial_t); + ringlen -= sizeof(key_serial_t) + ) + kcount += recursive_key_scan_aux(key, *pk++, depth + 1, + func, data); + + free(ring); + } + +do_this_key: + kcount += func(parent, key, desc, desc_len, data); + free(desc); + return kcount; +} + +/* + * Depth-first apply a function over a keyring tree + */ +int recursive_key_scan(key_serial_t key, recursive_key_scanner_t func, void *data) +{ + return recursive_key_scan_aux(0, key, 0, func, data); +} + +/* + * Depth-first apply a function over session keyring tree + */ +int recursive_session_key_scan(recursive_key_scanner_t func, void *data) +{ + key_serial_t session = + keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 0); + if (session > 0) + return recursive_key_scan(session, func, data); + return 0; +} + +#ifdef NO_GLIBC_KEYERR +/*****************************************************************************/ +/* + * initialise error handling + */ +static void error_init(void) +{ + char *err; + + error_inited = 1; + + dlerror(); + + libc_perror = dlsym(RTLD_NEXT,"perror"); + if (!libc_perror) { + fprintf(stderr, "Failed to look up next perror\n"); + err = dlerror(); + if (err) + fprintf(stderr, "%s\n", err); + abort(); + } + + //fprintf(stderr, "next perror at %p\n", libc_perror); + + libc_strerror_r = dlsym(RTLD_NEXT,"strerror_r"); + if (!libc_strerror_r) { + fprintf(stderr, "Failed to look up next strerror_r\n"); + err = dlerror(); + if (err) + fprintf(stderr, "%s\n", err); + abort(); + } + + //fprintf(stderr, "next strerror_r at %p\n", libc_strerror_r); + +#if 0 + libc_xpg_strerror_r = dlsym(RTLD_NEXT,"xpg_strerror_r"); + if (!libc_xpg_strerror_r) { + fprintf(stderr, "Failed to look up next xpg_strerror_r\n"); + err = dlerror(); + if (err) + fprintf(stderr, "%s\n", err); + abort(); + } + + //fprintf(stderr, "next xpg_strerror_r at %p\n", libc_xpg_strerror_r); +#endif + +} /* end error_init() */ + +/*****************************************************************************/ +/* + * overload glibc's strerror_r() with a version that knows about key errors + */ +char *strerror_r(int errnum, char *buf, size_t n) +{ + const char *errstr; + int len; + + printf("hello\n"); + + if (!error_inited) + error_init(); + + switch (errnum) { + case ENOKEY: + errstr = "Requested key not available"; + break; + + case EKEYEXPIRED: + errstr = "Key has expired"; + break; + + case EKEYREVOKED: + errstr = "Key has been revoked"; + break; + + case EKEYREJECTED: + errstr = "Key was rejected by service"; + break; + + default: + return libc_strerror_r(errnum, buf, n); + } + + len = strlen(errstr) + 1; + if (n > len) { + errno = ERANGE; + if (n > 0) { + memcpy(buf, errstr, n - 1); + buf[n - 1] = 0; + } + return NULL; + } + else { + memcpy(buf, errstr, len); + return buf; + } + +} /* end strerror_r() */ + +#if 0 +/*****************************************************************************/ +/* + * overload glibc's strerror_r() with a version that knows about key errors + */ +int xpg_strerror_r(int errnum, char *buf, size_t n) +{ + const char *errstr; + int len; + + if (!error_inited) + error_init(); + + switch (errnum) { + case ENOKEY: + errstr = "Requested key not available"; + break; + + case EKEYEXPIRED: + errstr = "Key has expired"; + break; + + case EKEYREVOKED: + errstr = "Key has been revoked"; + break; + + case EKEYREJECTED: + errstr = "Key was rejected by service"; + break; + + default: + return libc_xpg_strerror_r(errnum, buf, n); + } + + len = strlen(errstr) + 1; + if (n > len) { + errno = ERANGE; + if (n > 0) { + memcpy(buf, errstr, n - 1); + buf[n - 1] = 0; + } + return -1; + } + else { + memcpy(buf, errstr, len); + return 0; + } + +} /* end xpg_strerror_r() */ +#endif + +/*****************************************************************************/ +/* + * + */ +void perror(const char *msg) +{ + if (!error_inited) + error_init(); + + switch (errno) { + case ENOKEY: + fprintf(stderr, "%s: Requested key not available\n", msg); + return; + + case EKEYEXPIRED: + fprintf(stderr, "%s: Key has expired\n", msg); + return; + + case EKEYREVOKED: + fprintf(stderr, "%s: Key has been revoked\n", msg); + return; + + case EKEYREJECTED: + fprintf(stderr, "%s: Key was rejected by service\n", msg); + return; + + default: + libc_perror(msg); + return; + } + +} /* end perror() */ +#endif |