823 lines
17 KiB
C
823 lines
17 KiB
C
/* 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);
|
|
}
|
|
|
|
long keyctl_get_persistent(uid_t uid, key_serial_t id)
|
|
{
|
|
return keyctl(KEYCTL_GET_PERSISTENT, uid, id);
|
|
}
|
|
|
|
long keyctl_dh_compute(key_serial_t priv, key_serial_t prime,
|
|
key_serial_t base, char *buffer, size_t buflen)
|
|
{
|
|
struct keyctl_dh_params params = { .priv = priv,
|
|
.prime = prime,
|
|
.base = base };
|
|
|
|
return keyctl(KEYCTL_DH_COMPUTE, ¶ms, buffer, buflen, 0);
|
|
}
|
|
|
|
long keyctl_dh_compute_kdf(key_serial_t priv, key_serial_t prime,
|
|
key_serial_t base, char *hashname, char *otherinfo,
|
|
size_t otherinfolen, char *buffer, size_t buflen)
|
|
{
|
|
struct keyctl_dh_params params = { .priv = priv,
|
|
.prime = prime,
|
|
.base = base };
|
|
struct keyctl_kdf_params kdfparams = { .hashname = hashname,
|
|
.otherinfo = otherinfo,
|
|
.otherinfolen = otherinfolen };
|
|
|
|
return keyctl(KEYCTL_DH_COMPUTE, ¶ms, buffer, buflen, &kdfparams);
|
|
}
|
|
|
|
long keyctl_restrict_keyring(key_serial_t keyring, const char *type,
|
|
const char *restriction)
|
|
{
|
|
return keyctl(KEYCTL_RESTRICT_KEYRING, keyring, type, restriction);
|
|
}
|
|
|
|
long keyctl_pkey_query(key_serial_t key_id,
|
|
const char *info,
|
|
struct keyctl_pkey_query *result)
|
|
{
|
|
return keyctl(KEYCTL_PKEY_QUERY, key_id, info, result);
|
|
}
|
|
|
|
long keyctl_pkey_encrypt(key_serial_t key_id,
|
|
const char *info,
|
|
const void *data, size_t data_len,
|
|
void *enc, size_t enc_len)
|
|
{
|
|
struct keyctl_pkey_params params = {
|
|
.key_id = key_id,
|
|
.in_len = data_len,
|
|
.out_len = enc_len,
|
|
};
|
|
|
|
return keyctl(KEYCTL_PKEY_ENCRYPT, ¶ms, info, data, enc);
|
|
}
|
|
|
|
long keyctl_pkey_decrypt(key_serial_t key_id,
|
|
const char *info,
|
|
const void *enc, size_t enc_len,
|
|
void *data, size_t data_len)
|
|
{
|
|
struct keyctl_pkey_params params = {
|
|
.key_id = key_id,
|
|
.in_len = enc_len,
|
|
.out_len = data_len,
|
|
};
|
|
|
|
return keyctl(KEYCTL_PKEY_DECRYPT, ¶ms, info, enc, data);
|
|
}
|
|
|
|
long keyctl_pkey_sign(key_serial_t key_id,
|
|
const char *info,
|
|
const void *data, size_t data_len,
|
|
void *sig, size_t sig_len)
|
|
{
|
|
struct keyctl_pkey_params params = {
|
|
.key_id = key_id,
|
|
.in_len = data_len,
|
|
.out_len = sig_len,
|
|
};
|
|
|
|
return keyctl(KEYCTL_PKEY_SIGN, ¶ms, info, data, sig);
|
|
}
|
|
|
|
long keyctl_pkey_verify(key_serial_t key_id,
|
|
const char *info,
|
|
const void *data, size_t data_len,
|
|
const void *sig, size_t sig_len)
|
|
{
|
|
struct keyctl_pkey_params params = {
|
|
.key_id = key_id,
|
|
.in_len = data_len,
|
|
.in2_len = sig_len,
|
|
};
|
|
|
|
return keyctl(KEYCTL_PKEY_VERIFY, ¶ms, info, data, sig);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*
|
|
* 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;
|
|
|
|
for (;;) {
|
|
buflen = ret;
|
|
buf = malloc(buflen);
|
|
if (!buf)
|
|
return -1;
|
|
|
|
ret = keyctl_describe(id, buf, buflen);
|
|
if (ret < 0) {
|
|
free(buf);
|
|
return -1;
|
|
}
|
|
|
|
if (buflen >= ret)
|
|
break;
|
|
free(buf);
|
|
}
|
|
|
|
*_buffer = buf;
|
|
return ret - 1;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*
|
|
* 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)
|
|
{
|
|
char *buf;
|
|
long buflen, ret;
|
|
|
|
ret = keyctl_read(id, NULL, 0);
|
|
if (ret < 0)
|
|
return -1;
|
|
|
|
for (;;) {
|
|
buflen = ret;
|
|
buf = malloc(buflen + 1);
|
|
if (!buf)
|
|
return -1;
|
|
|
|
ret = keyctl_read(id, buf, buflen);
|
|
if (ret < 0) {
|
|
free(buf);
|
|
return -1;
|
|
}
|
|
|
|
if (buflen >= ret)
|
|
break;
|
|
free(buf);
|
|
}
|
|
|
|
buf[ret] = 0;
|
|
*_buffer = buf;
|
|
return ret;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*
|
|
* 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;
|
|
|
|
for (;;) {
|
|
buflen = ret;
|
|
buf = malloc(buflen);
|
|
if (!buf)
|
|
return -1;
|
|
|
|
ret = keyctl_get_security(id, buf, buflen);
|
|
if (ret < 0) {
|
|
free(buf);
|
|
return -1;
|
|
}
|
|
|
|
if (buflen >= ret)
|
|
break;
|
|
free(buf);
|
|
}
|
|
|
|
*_buffer = buf;
|
|
return ret - 1;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*
|
|
* fetch DH computation results into an allocated buffer
|
|
* - resulting buffer has an extra NUL added to the end
|
|
* - returns count (not including extraneous NUL)
|
|
*/
|
|
int keyctl_dh_compute_alloc(key_serial_t priv, key_serial_t prime,
|
|
key_serial_t base, void **_buffer)
|
|
{
|
|
char *buf;
|
|
long buflen, ret;
|
|
|
|
ret = keyctl_dh_compute(priv, prime, base, NULL, 0);
|
|
if (ret < 0)
|
|
return -1;
|
|
|
|
buflen = ret;
|
|
buf = malloc(buflen + 1);
|
|
if (!buf)
|
|
return -1;
|
|
|
|
ret = keyctl_dh_compute(priv, prime, base, buf, buflen);
|
|
if (ret < 0) {
|
|
free(buf);
|
|
return -1;
|
|
}
|
|
|
|
buf[ret] = 0;
|
|
*_buffer = buf;
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* 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;
|
|
}
|
|
|
|
/*
|
|
* Find a key by type and description
|
|
*/
|
|
key_serial_t find_key_by_type_and_desc(const char *type, const char *desc,
|
|
key_serial_t destringid)
|
|
{
|
|
key_serial_t id, error;
|
|
FILE *f;
|
|
char buf[1024], typebuf[40], rdesc[1024], *kdesc, *cp;
|
|
int n, ndesc, dlen;
|
|
|
|
error = ENOKEY;
|
|
|
|
id = request_key(type, desc, NULL, destringid);
|
|
if (id >= 0 || errno == ENOMEM)
|
|
return id;
|
|
if (errno != ENOKEY)
|
|
error = errno;
|
|
|
|
dlen = strlen(desc);
|
|
|
|
f = fopen("/proc/keys", "r");
|
|
if (!f) {
|
|
fprintf(stderr, "libkeyutils: Can't open /proc/keys: %m\n");
|
|
return -1;
|
|
}
|
|
|
|
while (fgets(buf, sizeof(buf), f)) {
|
|
cp = strchr(buf, '\n');
|
|
if (*cp)
|
|
*cp = '\0';
|
|
|
|
ndesc = 0;
|
|
n = sscanf(buf, "%x %*s %*u %*s %*x %*d %*d %s %n",
|
|
&id, typebuf, &ndesc);
|
|
if (n == 2 && ndesc > 0 && ndesc <= cp - buf) {
|
|
if (strcmp(typebuf, type) != 0)
|
|
continue;
|
|
kdesc = buf + ndesc;
|
|
if (memcmp(kdesc, desc, dlen) != 0)
|
|
continue;
|
|
if (kdesc[dlen] != ':' &&
|
|
kdesc[dlen] != '\0' &&
|
|
kdesc[dlen] != ' ')
|
|
continue;
|
|
kdesc[dlen] = '\0';
|
|
|
|
/* The key type appends extra stuff to the end of the
|
|
* description after a colon in /proc/keys. Colons,
|
|
* however, are allowed in descriptions, so we need to
|
|
* make a further check. */
|
|
n = keyctl_describe(id, rdesc, sizeof(rdesc) - 1);
|
|
if (n == -1) {
|
|
if (errno != ENOKEY)
|
|
error = errno;
|
|
if (errno == ENOMEM)
|
|
break;
|
|
}
|
|
if (n >= sizeof(rdesc) - 1)
|
|
continue;
|
|
rdesc[n] = '\0';
|
|
|
|
cp = strrchr(rdesc, ';');
|
|
if (!cp)
|
|
continue;
|
|
cp++;
|
|
if (strcmp(cp, desc) != 0)
|
|
continue;
|
|
|
|
fclose(f);
|
|
|
|
if (destringid &&
|
|
keyctl_link(id, destringid) == -1)
|
|
return -1;
|
|
|
|
return id;
|
|
}
|
|
}
|
|
|
|
fclose(f);
|
|
errno = error;
|
|
return -1;
|
|
}
|
|
|
|
#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
|