summaryrefslogtreecommitdiff
path: root/keyutils-1.5.6/request-key.c
diff options
context:
space:
mode:
Diffstat (limited to 'keyutils-1.5.6/request-key.c')
-rw-r--r--keyutils-1.5.6/request-key.c870
1 files changed, 870 insertions, 0 deletions
diff --git a/keyutils-1.5.6/request-key.c b/keyutils-1.5.6/request-key.c
new file mode 100644
index 0000000..3762e9a
--- /dev/null
+++ b/keyutils-1.5.6/request-key.c
@@ -0,0 +1,870 @@
+/* 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, eg: "/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 <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/select.h>
+#include <sys/wait.h>
+#include "keyutils.h"
+
+
+static int xdebug;
+static int xnolog;
+static char *xkey;
+static char *xuid;
+static char *xgid;
+static char *xthread_keyring;
+static char *xprocess_keyring;
+static char *xsession_keyring;
+static char conffile[256];
+static int confline;
+static int norecurse;
+
+static void lookup_action(char *op,
+ key_serial_t key,
+ char *ktype,
+ char *kdesc,
+ char *callout_info)
+ __attribute__((noreturn));
+
+static void execute_program(char *op,
+ key_serial_t key,
+ char *ktype,
+ char *kdesc,
+ char *callout_info,
+ char *cmdline)
+ __attribute__((noreturn));
+
+static void pipe_to_program(char *op,
+ key_serial_t key,
+ char *ktype,
+ char *kdesc,
+ char *callout_info,
+ char *prog,
+ char **argv)
+ __attribute__((noreturn));
+
+static int match(const char *pattern, int plen, const char *datum, int dlen);
+
+static void debug(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
+static void debug(const char *fmt, ...)
+{
+ va_list va;
+
+ if (xdebug) {
+ 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 (xdebug) {
+ 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[])
+{
+ key_serial_t key;
+ char *ktype, *kdesc, *buf, *callout_info;
+ int ret, ntype, dpos, n, fd;
+
+ 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);
+
+ for (;;) {
+ if (argc > 1 && strcmp(argv[1], "-d") == 0) {
+ xdebug++;
+ argv++;
+ argc--;
+ }
+ else if (argc > 1 && strcmp(argv[1], "-n") == 0) {
+ xnolog = 1;
+ argv++;
+ argc--;
+ }
+ else
+ break;
+ }
+
+ if (argc != 8 && argc != 9)
+ 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");
+ }
+
+ xkey = argv[2];
+ xuid = argv[3];
+ xgid = argv[4];
+ xthread_keyring = argv[5];
+ xprocess_keyring = argv[6];
+ xsession_keyring = argv[7];
+
+ key = atoi(xkey);
+
+ /* assume authority over the key
+ * - older kernel doesn't support this function
+ */
+ ret = keyctl_assume_authority(key);
+ if (ret < 0 && !(argc == 9 || errno == EOPNOTSUPP))
+ error("Failed to assume authority over key %d (%m)\n", key);
+
+ /* ask the kernel to describe the key to us */
+ if (xdebug < 2) {
+ ret = keyctl_describe_alloc(key, &buf);
+ if (ret < 0)
+ goto inaccessible;
+ }
+ else {
+ buf = strdup("user;0;0;1f0000;debug:1234");
+ }
+
+ /* 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");
+
+ ktype = buf;
+ ktype[ntype] = 0;
+ kdesc = buf + dpos;
+
+ debug("Key type: %s\n", ktype);
+ debug("Key desc: %s\n", kdesc);
+
+ /* get hold of the callout info */
+ callout_info = argv[8];
+
+ if (!callout_info) {
+ void *tmp;
+
+ if (keyctl_read_alloc(KEY_SPEC_REQKEY_AUTH_KEY, &tmp) < 0)
+ error("Failed to retrieve callout info (%m)\n");
+
+ callout_info = tmp;
+ }
+
+ debug("CALLOUT: '%s'\n", callout_info);
+
+ /* determine the action to perform */
+ lookup_action(argv[1], /* op */
+ key, /* ID of key under construction */
+ ktype, /* key type */
+ kdesc, /* key description */
+ callout_info /* call out information */
+ );
+
+inaccessible:
+ error("Key %d is inaccessible (%m)\n", key);
+
+} /* end main() */
+
+/*****************************************************************************/
+/*
+ * determine the action to perform
+ */
+static void lookup_action(char *op,
+ key_serial_t key,
+ char *ktype,
+ char *kdesc,
+ char *callout_info)
+{
+ char buf[4096 + 2], *p, *q;
+ FILE *conf;
+ int len, oplen, ktlen, kdlen, cilen;
+
+ oplen = strlen(op);
+ ktlen = strlen(ktype);
+ kdlen = strlen(kdesc);
+ cilen = strlen(callout_info);
+
+ /* search the config file for a command to run */
+ if (strlen(ktype) <= sizeof(conffile) - 30) {
+ if (xdebug < 2)
+ snprintf(conffile, sizeof(conffile) - 1,
+ "/etc/request-key.d/%s.conf", ktype);
+ else
+ snprintf(conffile, sizeof(conffile) - 1,
+ "request-key.d/%s.conf", ktype);
+ conf = fopen(conffile, "r");
+ if (conf)
+ goto opened_conf_file;
+ if (errno != ENOENT)
+ error("Cannot open %s: %m\n", conffile);
+ }
+
+ if (xdebug < 2)
+ snprintf(conffile, sizeof(conffile) - 1, "/etc/request-key.conf");
+ else
+ snprintf(conffile, sizeof(conffile) - 1, "request-key.conf");
+ conf = fopen(conffile, "r");
+ if (!conf)
+ error("Cannot open %s: %m\n", conffile);
+
+opened_conf_file:
+ debug("Opened config file '%s'\n", conffile);
+
+ for (confline = 1;; confline++) {
+ /* read the file line-by-line */
+ if (!fgets(buf, sizeof(buf), conf)) {
+ if (feof(conf))
+ error("Cannot find command to construct key %d\n", key);
+ 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, op, oplen))
+ 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, ktype, ktlen))
+ 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, kdesc, kdlen))
+ 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, callout_info, cilen))
+ continue;
+
+ p++;
+
+ debug("%s:%d: Line matches\n", conffile, confline);
+
+ /* we've got an action */
+ while (isspace(*p)) p++;
+ if (!*p)
+ goto syntax_error;
+
+ fclose(conf);
+
+ execute_program(op, key, ktype, kdesc, callout_info, p);
+ }
+
+ file_error("No matching action\n");
+
+syntax_error:
+ line_error("Syntax error\n");
+
+} /* end lookup_action() */
+
+/*****************************************************************************/
+/*
+ * 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
+ */
+static int match(const char *pattern, int plen, const char *datum, int dlen)
+{
+ const char *asterisk;
+ int n;
+
+ debug("match(%*.*s,%*.*s)\n", 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; /* "*" matches everything */
+
+ /* match the end of the datum */
+ plen--;
+ if (memcmp(pattern, datum + (dlen - plen), plen) == 0)
+ goto yes;
+ 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; /* "abc*" matches */
+
+ /* match the end of the datum */
+ asterisk++;
+ n = plen - n - 1;
+ if (memcmp(pattern, datum + (dlen - n), n) == 0)
+ goto yes;
+
+no:
+ debug(" = no\n");
+ return 0;
+
+yes:
+ debug(" = yes\n");
+ return 1;
+
+} /* end match() */
+
+/*****************************************************************************/
+/*
+ * execute a program to deal with a key
+ */
+static void execute_program(char *op,
+ key_serial_t key,
+ char *ktype,
+ char *kdesc,
+ char *callout_info,
+ char *cmdline)
+{
+ char *argv[256];
+ char *prog, *p, *q;
+ int argc, pipeit;
+
+ debug("execute_program('%s','%s')\n", 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] = op; continue;
+ case 'k': argv[argc] = xkey; continue;
+ case 't': argv[argc] = ktype; continue;
+ case 'd': argv[argc] = kdesc; continue;
+ case 'c': argv[argc] = callout_info; continue;
+ case 'u': argv[argc] = xuid; continue;
+ case 'g': argv[argc] = xgid; continue;
+ case 'T': argv[argc] = xthread_keyring; continue;
+ case 'P': argv[argc] = xprocess_keyring; continue;
+ case 'S': argv[argc] = xsession_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 (xdebug) {
+ 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 (pipeit)
+ pipe_to_program(op, key, ktype, kdesc, callout_info, 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(char *op,
+ key_serial_t key,
+ char *ktype,
+ char *kdesc,
+ char *callout_info,
+ 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)", 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 = strlen(callout_info);
+ pc = 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 (xdebug)
+ 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 (xdebug)
+ 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));
+ lookup_action("negate", key, ktype, kdesc, callout_info);
+ }
+
+ if (WIFSIGNALED(tmp)) {
+ if (norecurse)
+ error("child died on signal %d\n", WTERMSIG(tmp));
+
+ norecurse = 1;
+ debug("child died on signal %d\n", WTERMSIG(tmp));
+ lookup_action("negate", key, ktype, kdesc, callout_info);
+ }
+
+ /* attempt to instantiate the key */
+ debug("instantiate with %td bytes\n", pp - payload);
+
+ if (keyctl_instantiate(key, payload, pp - payload, 0) < 0)
+ error("instantiate key failed: %m\n");
+
+ debug("instantiation successful\n");
+ exit(0);
+
+} /* end pipe_to_program() */