diff options
author | Mikhail Bautin <mbautin@users.noreply.github.com> | 2022-05-19 12:08:12 -0700 |
---|---|---|
committer | Mikhail Bautin <mbautin@users.noreply.github.com> | 2022-05-19 12:08:12 -0700 |
commit | 4b0753269f45d2aa254827bb720e96056a074539 (patch) | |
tree | db284d87c3eac170a4b7bbe23dd6019cd1efec0e /request-key.c |
Imoprt from https://people.redhat.com/~dhowells/keyutils/keyutils-1.6.1.tar.bz2v1.6.1
Diffstat (limited to 'request-key.c')
-rw-r--r-- | request-key.c | 955 |
1 files changed, 955 insertions, 0 deletions
diff --git a/request-key.c b/request-key.c new file mode 100644 index 0000000..bf47c0a --- /dev/null +++ b/request-key.c @@ -0,0 +1,955 @@ +/* request-key.c: hand a key request off to the appropriate process + * + * Copyright (C) 2005 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 General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * /sbin/request-key <op> <key> <uid> <gid> <threadring> <processring> <sessionring> [<info>] + * + * Searches the specified session ring for a key indicating the command to run: + * type: "user" + * desc: "request-key:<op>" + * data: command name, e.g.: "/home/dhowells/request-key-create.sh" + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <signal.h> +#include <syslog.h> +#include <unistd.h> +#include <dirent.h> +#include <limits.h> +#include <getopt.h> +#include <fcntl.h> +#include <errno.h> +#include <ctype.h> +#include <sys/select.h> +#include <sys/wait.h> +#include "keyutils.h" + + +struct parameters { + key_serial_t key_id; + char *op; + char *key_type; + char *key_desc; + char *callout_info; + char *key; + char *uid; + char *gid; + char *thread_keyring; + char *process_keyring; + char *session_keyring; + int len; + int oplen; + int ktlen; + int kdlen; + int cilen; + +}; + +static int verbosity; +static int xlocaldirs; +static int xnolog; +static int debug_mode; +static char conffile[PATH_MAX + 1]; +static int confline; +static int norecurse; + +static char cmd[4096 + 2], cmd_conffile[PATH_MAX + 1]; +static unsigned int cmd_wildness[4] = { UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX }; +static int cmd_len, cmd_confline; + +static void lookup_action(struct parameters *params) + __attribute__((noreturn)); +static void scan_conf_dir(struct parameters *params, const char *confdir); +static void scan_conf_file(struct parameters *params, int dirfd, const char *conffile); + +static void execute_program(struct parameters *params, + char *cmdline) + __attribute__((noreturn)); + +static void pipe_to_program(struct parameters *params, + char *prog, + char **argv) + __attribute__((noreturn)); + +static int match(const char *pattern, int plen, const char *datum, int dlen, + unsigned int *wildness); + +static void debug(const char *fmt, ...) __attribute__((format(printf, 1, 2))); +static void debug(const char *fmt, ...) +{ + va_list va; + + if (verbosity) { + va_start(va, fmt); + vfprintf(stderr, fmt, va); + va_end(va); + + if (!xnolog) { + openlog("request-key", 0, LOG_AUTHPRIV); + + va_start(va, fmt); + vsyslog(LOG_DEBUG, fmt, va); + va_end(va); + + closelog(); + } + } +} + +static void error(const char *fmt, ...) __attribute__((noreturn, format(printf, 1, 2))); +static void error(const char *fmt, ...) +{ + va_list va; + + if (verbosity) { + va_start(va, fmt); + vfprintf(stderr, fmt, va); + va_end(va); + } + + if (!xnolog) { + openlog("request-key", 0, LOG_AUTHPRIV); + + va_start(va, fmt); + vsyslog(LOG_ERR, fmt, va); + va_end(va); + + closelog(); + } + + exit(1); +} + +#define file_error(FMT, ...) error("%s: "FMT, conffile, ## __VA_ARGS__) +#define line_error(FMT, ...) error("%s:%d: "FMT, conffile, confline, ## __VA_ARGS__) + +static void oops(int x) +{ + error("Died on signal %d", x); +} + +/*****************************************************************************/ +/* + * + */ +int main(int argc, char *argv[]) +{ + struct parameters params; + char *test_desc = "user;0;0;1f0000;debug:1234"; + char *buf; + int ret, ntype, dpos, n, fd, opt; + + if (argc == 2 && strcmp(argv[1], "--version") == 0) { + printf("request-key from %s (Built %s)\n", + keyutils_version_string, keyutils_build_string); + return 0; + } + + signal(SIGSEGV, oops); + signal(SIGBUS, oops); + signal(SIGPIPE, SIG_IGN); + + while (opt = getopt(argc, argv, "D:dlnv"), + opt != -1) { + switch (opt) { + case 'D': + test_desc = optarg; + break; + case 'd': + debug_mode = 1; + break; + case 'l': + xlocaldirs = 1; + break; + case 'n': + xnolog = 1; + break; + case 'v': + verbosity++; + break; + } + } + + argc -= optind; + argv += optind; + + if (argc != 7 && argc != 8) + error("Unexpected argument count: %d\n", argc); + + fd = open("/dev/null", O_RDWR); + if (fd < 0) + error("open"); + if (fd > 2) { + close(fd); + } + else if (fd < 2) { + ret = dup(fd); + if (ret < 0) + error("dup failed: %m\n"); + + if (ret < 2 && dup(fd) < 0) + error("dup failed: %m\n"); + } + + params.op = argv[0]; + params.key = argv[1]; + params.uid = argv[2]; + params.gid = argv[3]; + params.thread_keyring = argv[4]; + params.process_keyring = argv[5]; + params.session_keyring = argv[6]; + params.callout_info = argv[7]; + + params.key_id = atoi(params.key); + + /* assume authority over the key + * - older kernel doesn't support this function + */ + if (!debug_mode) { + ret = keyctl_assume_authority(params.key_id); + if (ret < 0 && !(argc == 8 || errno == EOPNOTSUPP)) + error("Failed to assume authority over key %d (%m)\n", + params.key_id); + } + + /* ask the kernel to describe the key to us */ + if (!debug_mode) { + ret = keyctl_describe_alloc(params.key_id, &buf); + if (ret < 0) + goto inaccessible; + } else { + buf = strdup(test_desc); + } + + /* extract the type and description from the key */ + debug("Key descriptor: \"%s\"\n", buf); + ntype = -1; + dpos = -1; + + n = sscanf(buf, "%*[^;]%n;%*d;%*d;%x;%n", &ntype, &n, &dpos); + if (n != 1) + error("Failed to parse key description\n"); + + params.key_type = buf; + params.key_type[ntype] = 0; + params.key_desc = buf + dpos; + + debug("Key type: %s\n", params.key_type); + debug("Key desc: %s\n", params.key_desc); + + /* get hold of the callout info */ + if (!params.callout_info) { + void *tmp; + + if (keyctl_read_alloc(KEY_SPEC_REQKEY_AUTH_KEY, &tmp) < 0) + error("Failed to retrieve callout info (%m)\n"); + + params.callout_info = tmp; + } + + debug("CALLOUT: '%s'\n", params.callout_info); + + /* determine the action to perform */ + params.oplen = strlen(params.op); + params.ktlen = strlen(params.key_type); + params.kdlen = strlen(params.key_desc); + params.cilen = strlen(params.callout_info); + lookup_action(¶ms); + +inaccessible: + error("Key %d is inaccessible (%m)\n", params.key_id); + +} /* end main() */ + +/*****************************************************************************/ +/* + * determine the action to perform + */ +static void lookup_action(struct parameters *params) +{ + if (!xlocaldirs) { + scan_conf_dir(params, "/etc/request-key.d"); + scan_conf_file(params, AT_FDCWD, "/etc/request-key.conf"); + } else { + scan_conf_dir(params, "request-key.d"); + scan_conf_file(params, AT_FDCWD, "request-key.conf"); + } + + if (cmd_len > 0) + execute_program(params, cmd); + + file_error("No matching action\n"); +} + +/*****************************************************************************/ +/* + * Scan the files in a configuration directory. + */ +static void scan_conf_dir(struct parameters *params, const char *confdir) +{ + struct dirent *d; + DIR *dir; + int l; + + debug("__ SCAN %s __\n", confdir); + + dir = opendir(confdir); + if (!dir) { + if (errno == ENOENT) + return; + error("Cannot open %s: %m\n", confdir); + } + + while ((d = readdir(dir))) { + if (d->d_name[0] == '.') + continue; + if (d->d_type != DT_UNKNOWN && d->d_type != DT_REG) + continue; + l = strlen(d->d_name); + if (l < 5) + continue; + if (memcmp(d->d_name + l - 5, ".conf", 5) != 0) + continue; + scan_conf_file(params, dirfd(dir), d->d_name); + } + + closedir(dir); +} + +/*****************************************************************************/ +/* + * Scan the contents of a configuration file. + */ +static void scan_conf_file(struct parameters *params, int dirfd, const char *conffile) +{ + char buf[4096 + 2], *p, *q; + FILE *conf; + int fd; + + debug("__ read %s __\n", conffile); + + fd = openat(dirfd, conffile, O_RDONLY); + if (fd < 0) { + if (errno == ENOENT) + return; + error("Cannot open %s: %m\n", conffile); + } + + conf = fdopen(fd, "r"); + if (!conf) + error("Cannot open %s: %m\n", conffile); + + for (confline = 1;; confline++) { + unsigned int wildness[4] = {}; + unsigned int len; + + /* read the file line-by-line */ + if (!fgets(buf, sizeof(buf), conf)) { + if (feof(conf)) + break; + file_error("error %m\n"); + } + + len = strlen(buf); + if (len >= sizeof(buf) - 2) + line_error("Line too long\n"); + + /* ignore blank lines and comments */ + if (len == 1 || buf[0] == '#' || isspace(buf[0])) + continue; + + buf[--len] = 0; + p = buf; + + /* attempt to match the op */ + q = p; + while (*p && !isspace(*p)) p++; + if (!*p) + goto syntax_error; + *p = 0; + + if (!match(q, p - q, params->op, params->oplen, &wildness[0])) + continue; + + p++; + + /* attempt to match the type */ + while (isspace(*p)) p++; + if (!*p) + goto syntax_error; + + q = p; + while (*p && !isspace(*p)) p++; + if (!*p) + goto syntax_error; + *p = 0; + + if (!match(q, p - q, params->key_type, params->ktlen, &wildness[1])) + continue; + + p++; + + /* attempt to match the description */ + while (isspace(*p)) p++; + if (!*p) + goto syntax_error; + + q = p; + while (*p && !isspace(*p)) p++; + if (!*p) + goto syntax_error; + *p = 0; + + if (!match(q, p - q, params->key_desc, params->kdlen, &wildness[2])) + continue; + + p++; + + /* attempt to match the callout info */ + while (isspace(*p)) p++; + if (!*p) + goto syntax_error; + + q = p; + while (*p && !isspace(*p)) p++; + if (!*p) + goto syntax_error; + *p = 0; + + if (!match(q, p - q, params->callout_info, params->cilen, &wildness[3])) + continue; + + p++; + + /* we've got a match */ + while (isspace(*p)) p++; + if (!*p) + goto syntax_error; + + debug("%s:%d: Line matches '%s' (%u,%u,%u,%u)\n", + conffile, confline, p, + wildness[0], wildness[1], wildness[2], wildness[3]); + + if (wildness[0] < cmd_wildness[0] || + (wildness[0] == cmd_wildness[0] && + wildness[1] < cmd_wildness[1]) || + (wildness[0] == cmd_wildness[0] && + wildness[1] == cmd_wildness[1] && + wildness[2] < cmd_wildness[2]) || + (wildness[0] == cmd_wildness[0] && + wildness[1] == cmd_wildness[1] && + wildness[2] == cmd_wildness[2] && + wildness[3] < cmd_wildness[3]) + ) { + memcpy(cmd_wildness, wildness, sizeof(cmd_wildness)); + cmd_len = len - (p - buf); + cmd_confline = confline; + debug("%s:%d: Prefer command (%u,%u,%u,%u)\n", + conffile, confline, + wildness[0], wildness[1], wildness[2], wildness[3]); + memcpy(cmd, p, cmd_len + 1); + strcpy(cmd_conffile, conffile); + } + } + + fclose(conf); + return; + +syntax_error: + line_error("Syntax error\n"); +} + +/*****************************************************************************/ +/* + * attempt to match a datum to a pattern + * - one asterisk is allowed anywhere in the pattern to indicate a wildcard + * - returns true if matched, false if not + * - adds the total number of chars skipped by wildcard to *_wildness + */ +static int match(const char *pattern, int plen, const char *datum, int dlen, + unsigned int *_wildness) +{ + const char *asterisk; + int n; + + if (verbosity >= 2) + debug("match(%*.*s,%*.*s)", plen, plen, pattern, dlen, dlen, datum); + + asterisk = memchr(pattern, '*', plen); + if (!asterisk) { + /* exact match only if no wildcard */ + if (plen == dlen && memcmp(pattern, datum, dlen) == 0) + goto yes; + goto no; + } + + /* the datum mustn't be shorter than the pattern without the asterisk */ + if (dlen < plen - 1) + goto no; + + n = asterisk - pattern; + if (n == 0) { + /* wildcard at beginning of pattern */ + pattern++; + if (!*pattern) + goto yes_wildcard; /* "*" matches everything */ + + /* match the end of the datum */ + if (memcmp(pattern, datum + (dlen - (plen - 1)), plen - 1) == 0) + goto yes_wildcard; + goto no; + } + + /* need to match beginning of datum for "abc*" and "abc*def" */ + if (memcmp(pattern, datum, n) != 0) + goto no; + + if (!asterisk[1]) + goto yes_wildcard; /* "abc*" matches */ + + /* match the end of the datum */ + asterisk++; + n = plen - n - 1; + if (memcmp(pattern, datum + (dlen - n), n) == 0) + goto yes_wildcard; + +no: + if (verbosity >= 2) + debug(" = no\n"); + return 0; + +yes: + if (verbosity >= 2) + debug(" = yes (w=0)\n"); + return 1; + +yes_wildcard: + *_wildness += dlen - (plen - 1); + if (verbosity >= 2) + debug(" = yes (w=%u)\n", dlen - (plen - 1)); + return 1; + +} /* end match() */ + +/*****************************************************************************/ +/* + * execute a program to deal with a key + */ +static void execute_program(struct parameters *params, char *cmdline) +{ + char *argv[256]; + char *prog, *p, *q; + int argc, pipeit; + + debug("execute_program('%s','%s')\n", params->callout_info, cmdline); + + /* if the commandline begins with a bar, then we pipe the callout data into it and read + * back the payload data + */ + pipeit = 0; + + if (cmdline[0] == '|') { + pipeit = 1; + cmdline++; + } + + /* extract the path to the program to run */ + prog = p = cmdline; + while (*p && !isspace(*p)) p++; +// if (!*p) +// line_error("No command path\n"); +// *p++ = 0; + if (*p) + *p++ = 0; + + argv[0] = strrchr(prog, '/') + 1; + + /* extract the arguments */ + for (argc = 1; p; argc++) { + while (isspace(*p)) p++; + if (!*p) + break; + + if (argc >= 254) + line_error("Too many arguments\n"); + argv[argc] = q = p; + + while (*p && !isspace(*p)) p++; + + if (*p) + *p++ = 0; + else + p = NULL; + + debug("argv[%d]: '%s'\n", argc, argv[argc]); + + if (*q != '%') + continue; + + /* it's a macro */ + q++; + if (!*q) + line_error("Missing macro name\n"); + + if (*q == '%') { + /* it's actually an anti-macro escape "%%..." -> "%..." */ + argv[argc]++; + continue; + } + + /* single character macros */ + if (!q[1]) { + switch (*q) { + case 'o': argv[argc] = params->op; continue; + case 'k': argv[argc] = params->key; continue; + case 't': argv[argc] = params->key_type; continue; + case 'd': argv[argc] = params->key_desc; continue; + case 'c': argv[argc] = params->callout_info; continue; + case 'u': argv[argc] = params->uid; continue; + case 'g': argv[argc] = params->gid; continue; + case 'T': argv[argc] = params->thread_keyring; continue; + case 'P': argv[argc] = params->process_keyring; continue; + case 'S': argv[argc] = params->session_keyring; continue; + default: + line_error("Unsupported macro\n"); + } + } + + /* keysub macro */ + if (*q == '{') { + key_serial_t keysub; + void *tmp; + char *ksdesc, *end, *subdata; + int ret, loop; + + /* extract type and description */ + q++; + ksdesc = strchr(q, ':'); + if (!ksdesc) + line_error("Keysub macro lacks ':'\n"); + *ksdesc++ = 0; + end = strchr(ksdesc, '}'); + if (!end) + line_error("Unterminated keysub macro\n"); + + *end++ = 0; + if (*end) + line_error("Keysub macro has trailing rubbish\n"); + + debug("Keysub: %s key \"%s\"\n", q, ksdesc); + + if (!q[0]) + line_error("Keysub type empty\n"); + + if (!ksdesc[0]) + line_error("Keysub description empty\n"); + + /* look up the key in the requestor's keyrings, but fail immediately if the + * key is not found rather than invoking /sbin/request-key again + */ + keysub = request_key(q, ksdesc, NULL, 0); + if (keysub < 0) + line_error("Keysub key not found: %m\n"); + + ret = keyctl_read_alloc(keysub, &tmp); + if (ret < 0) + line_error("Can't read keysub %d data: %m\n", keysub); + subdata = tmp; + + for (loop = 0; loop < ret; loop++) + if (!isprint(subdata[loop])) + error("keysub %d data not printable ('%02hhx')\n", + keysub, subdata[loop]); + + argv[argc] = subdata; + continue; + } + } + + if (argc == 0) + line_error("No arguments\n"); + + argv[argc] = NULL; + + if (verbosity) { + char **ap; + + debug("%s %s\n", pipeit ? "PipeThru" : "Run", prog); + for (ap = argv; *ap; ap++) + debug("- argv[%td] = \"%s\"\n", ap - argv, *ap); + } + + /* become the same UID/GID as the key requesting process */ + //setgid(atoi(xuid)); + //setuid(atoi(xgid)); + + /* if the last argument is a single bar, we spawn off the program dangling on the end of + * three pipes and read the key material from the program, otherwise we just exec + */ + if (debug_mode) { + printf("-- exec disabled --\n"); + exit(0); + } + + if (pipeit) + pipe_to_program(params, prog, argv); + + /* attempt to execute the command */ + execv(prog, argv); + + line_error("Failed to execute '%s': %m\n", prog); + +} /* end execute_program() */ + +/*****************************************************************************/ +/* + * pipe the callout information to the specified program and retrieve the + * payload data over another pipe + */ +static void pipe_to_program(struct parameters *params, char *prog, char **argv) +{ + char errbuf[512], payload[32768 + 1], *pp, *pc, *pe; + int ipi[2], opi[2], epi[2], childpid; + int ifl, ofl, efl, npay, ninfo, espace, tmp; + + debug("pipe_to_program(%s -> %s)", params->callout_info, prog); + + if (pipe(ipi) < 0 || pipe(opi) < 0 || pipe(epi) < 0) + error("pipe failed: %m"); + + childpid = fork(); + if (childpid == -1) + error("fork failed: %m"); + + if (childpid == 0) { + /* child process */ + if (dup2(ipi[0], 0) < 0 || + dup2(opi[1], 1) < 0 || + dup2(epi[1], 2) < 0) + error("dup2 failed: %m"); + close(ipi[0]); + close(ipi[1]); + close(opi[0]); + close(opi[1]); + close(epi[0]); + close(epi[1]); + + execv(prog, argv); + line_error("Failed to execute '%s': %m\n", prog); + } + + /* parent process */ + close(ipi[0]); + close(opi[1]); + close(epi[1]); + +#define TOSTDIN ipi[1] +#define FROMSTDOUT opi[0] +#define FROMSTDERR epi[0] + + ifl = fcntl(TOSTDIN, F_GETFL); + ofl = fcntl(FROMSTDOUT, F_GETFL); + efl = fcntl(FROMSTDERR, F_GETFL); + if (ifl < 0 || ofl < 0 || efl < 0) + error("fcntl/F_GETFL failed: %m"); + + ifl |= O_NONBLOCK; + ofl |= O_NONBLOCK; + efl |= O_NONBLOCK; + + if (fcntl(TOSTDIN, F_SETFL, ifl) < 0 || + fcntl(FROMSTDOUT, F_SETFL, ofl) < 0 || + fcntl(FROMSTDERR, F_SETFL, efl) < 0) + error("fcntl/F_SETFL failed: %m"); + + ninfo = params->cilen; + pc = params->callout_info; + + npay = sizeof(payload); + pp = payload; + + espace = sizeof(errbuf); + pe = errbuf; + + do { + fd_set rfds, wfds; + + FD_ZERO(&rfds); + FD_ZERO(&wfds); + + if (TOSTDIN != -1) { + if (ninfo > 0) { + FD_SET(TOSTDIN, &wfds); + } + else { + close(TOSTDIN); + TOSTDIN = -1; + continue; + } + } + + if (FROMSTDOUT != -1) + FD_SET(FROMSTDOUT, &rfds); + + if (FROMSTDERR != -1) + FD_SET(FROMSTDERR, &rfds); + + tmp = TOSTDIN > FROMSTDOUT ? TOSTDIN : FROMSTDOUT; + tmp = tmp > FROMSTDERR ? tmp : FROMSTDERR; + tmp++; + + debug("select r=%d,%d w=%d m=%d\n", FROMSTDOUT, FROMSTDERR, TOSTDIN, tmp); + + tmp = select(tmp, &rfds, &wfds, NULL, NULL); + if (tmp < 0) + error("select failed: %m\n"); + + if (TOSTDIN != -1 && FD_ISSET(TOSTDIN, &wfds)) { + tmp = write(TOSTDIN, pc, ninfo); + if (tmp < 0) { + if (errno != EPIPE) + error("write failed: %m\n"); + + debug("EPIPE"); + ninfo = 0; + } + else { + debug("wrote %d\n", tmp); + + pc += tmp; + ninfo -= tmp; + } + } + + if (FROMSTDOUT != -1 && FD_ISSET(FROMSTDOUT, &rfds)) { + tmp = read(FROMSTDOUT, pp, npay); + if (tmp < 0) + error("read failed: %m\n"); + + debug("read %d\n", tmp); + + if (tmp == 0) { + close(FROMSTDOUT); + FROMSTDOUT = -1; + } + else { + pp += tmp; + npay -= tmp; + + if (npay == 0) + error("Too much data read from query program\n"); + } + } + + if (FROMSTDERR != -1 && FD_ISSET(FROMSTDERR, &rfds)) { + char *nl; + + tmp = read(FROMSTDERR, pe, espace); + if (tmp < 0) + error("read failed: %m\n"); + + debug("read err %d\n", tmp); + + if (tmp == 0) { + close(FROMSTDERR); + FROMSTDERR = -1; + continue; + } + + pe += tmp; + espace -= tmp; + + while ((nl = memchr(errbuf, '\n', pe - errbuf))) { + int n, rest; + + nl++; + n = nl - errbuf; + + if (verbosity) + fprintf(stderr, "Child: %*.*s", n, n, errbuf); + + if (!xnolog) { + openlog("request-key", 0, LOG_AUTHPRIV); + syslog(LOG_ERR, "Child: %*.*s", n, n, errbuf); + closelog(); + } + + rest = pe - nl; + if (rest > 0) { + memmove(errbuf, nl, rest); + pe -= n; + espace += n; + } + else { + pe = errbuf; + espace = sizeof(errbuf); + } + } + + if (espace == 0) { + int n = sizeof(errbuf); + + if (verbosity) + fprintf(stderr, "Child: %*.*s", n, n, errbuf); + + if (!xnolog) { + openlog("request-key", 0, LOG_AUTHPRIV); + syslog(LOG_ERR, "Child: %*.*s", n, n, errbuf); + closelog(); + } + + pe = errbuf; + espace = sizeof(errbuf); + } + } + + } while (TOSTDIN != -1 || FROMSTDOUT != -1 || FROMSTDERR != -1); + + /* wait for the program to exit */ + if (waitpid(childpid, &tmp, 0) != childpid) + error("wait for child failed: %m\n"); + + /* if the process exited non-zero or died on a signal, then we call back in to ourself to + * decide on negation + * - this is not exactly beautiful but the quickest way of having configurable negation + * settings + */ + if (WIFEXITED(tmp) && WEXITSTATUS(tmp) != 0) { + if (norecurse) + error("child exited %d\n", WEXITSTATUS(tmp)); + + norecurse = 1; + debug("child exited %d\n", WEXITSTATUS(tmp)); + params->op = "negate"; + lookup_action(params); + } + + if (WIFSIGNALED(tmp)) { + if (norecurse) + error("child died on signal %d\n", WTERMSIG(tmp)); + + norecurse = 1; + params->op = "negate"; + lookup_action(params); + } + + /* attempt to instantiate the key */ + debug("instantiate with %td bytes\n", pp - payload); + + if (keyctl_instantiate(params->key_id, payload, pp - payload, 0) < 0) + error("instantiate key failed: %m\n"); + + debug("instantiation successful\n"); + exit(0); + +} /* end pipe_to_program() */ |