Add PIE compilation flags
[platform/upstream/keyutils.git] / request-key.c
1 /* request-key.c: hand a key request off to the appropriate process
2  *
3  * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU 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.
10  *
11  * /sbin/request-key <op> <key> <uid> <gid> <threadring> <processring> <sessionring> [<info>]
12  *
13  * Searches the specified session ring for a key indicating the command to run:
14  *      type:   "user"
15  *      desc:   "request-key:<op>"
16  *      data:   command name, eg: "/home/dhowells/request-key-create.sh"
17  */
18
19 #include <stdio.h>
20 #include <stdint.h>
21 #include <stdlib.h>
22 #include <stdarg.h>
23 #include <string.h>
24 #include <signal.h>
25 #include <syslog.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <errno.h>
29 #include <ctype.h>
30 #include <sys/select.h>
31 #include <sys/wait.h>
32 #include "keyutils.h"
33
34
35 static int xdebug;
36 static int xnolog;
37 static char *xkey;
38 static char *xuid;
39 static char *xgid;
40 static char *xthread_keyring;
41 static char *xprocess_keyring;
42 static char *xsession_keyring;
43 static int confline;
44 static int norecurse;
45
46 static void lookup_action(char *op,
47                           key_serial_t key,
48                           char *ktype,
49                           char *kdesc,
50                           char *callout_info)
51         __attribute__((noreturn));
52
53 static void execute_program(char *op,
54                             key_serial_t key,
55                             char *ktype,
56                             char *kdesc,
57                             char *callout_info,
58                             char *cmdline)
59         __attribute__((noreturn));
60
61 static void pipe_to_program(char *op,
62                             key_serial_t key,
63                             char *ktype,
64                             char *kdesc,
65                             char *callout_info,
66                             char *prog,
67                             char **argv)
68         __attribute__((noreturn));
69
70 static int match(const char *pattern, int plen, const char *datum, int dlen);
71
72 static void debug(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
73 static void debug(const char *fmt, ...)
74 {
75         va_list va;
76
77         if (xdebug) {
78                 va_start(va, fmt);
79                 vfprintf(stderr, fmt, va);
80                 va_end(va);
81
82                 if (!xnolog) {
83                         openlog("request-key", 0, LOG_AUTHPRIV);
84
85                         va_start(va, fmt);
86                         vsyslog(LOG_DEBUG, fmt, va);
87                         va_end(va);
88
89                         closelog();
90                 }
91         }
92 }
93
94 static void error(const char *fmt, ...) __attribute__((noreturn, format(printf, 1, 2)));
95 static void error(const char *fmt, ...)
96 {
97         va_list va;
98
99         if (xdebug) {
100                 va_start(va, fmt);
101                 vfprintf(stderr, fmt, va);
102                 va_end(va);
103         }
104
105         if (!xnolog) {
106                 openlog("request-key", 0, LOG_AUTHPRIV);
107
108                 va_start(va, fmt);
109                 vsyslog(LOG_ERR, fmt, va);
110                 va_end(va);
111
112                 closelog();
113         }
114
115         exit(1);
116 }
117
118 static void oops(int x)
119 {
120         error("Died on signal %d", x);
121 }
122
123 /*****************************************************************************/
124 /*
125  *
126  */
127 int main(int argc, char *argv[])
128 {
129         key_serial_t key;
130         char *ktype, *kdesc, *buf, *callout_info;
131         int ret, ntype, dpos, n, fd;
132
133         signal(SIGSEGV, oops);
134         signal(SIGBUS, oops);
135         signal(SIGPIPE, SIG_IGN);
136
137         for (;;) {
138                 if (argc > 1 && strcmp(argv[1], "-d") == 0) {
139                         xdebug++;
140                         argv++;
141                         argc--;
142                 }
143                 else if (argc > 1 && strcmp(argv[1], "-n") == 0) {
144                         xnolog = 1;
145                         argv++;
146                         argc--;
147                 }
148                 else
149                         break;
150         }
151
152         if (argc != 8 && argc != 9)
153                 error("Unexpected argument count: %d\n", argc);
154
155         fd = open("/dev/null", O_RDWR);
156         if (fd < 0)
157                 error("open");
158         if (fd > 2) {
159                 close(fd);
160         }
161         else if (fd < 2) {
162                 ret = dup(fd);
163                 if (ret < 0)
164                         error("dup failed: %m\n");
165
166                 if (ret < 2 && dup(fd) < 0)
167                         error("dup failed: %m\n");
168         }
169
170         xkey = argv[2];
171         xuid = argv[3];
172         xgid = argv[4];
173         xthread_keyring = argv[5];
174         xprocess_keyring = argv[6];
175         xsession_keyring = argv[7];
176
177         key = atoi(xkey);
178
179         /* assume authority over the key
180          * - older kernel doesn't support this function
181          */
182         ret = keyctl_assume_authority(key);
183         if (ret < 0 && !(argc == 9 || errno == EOPNOTSUPP))
184                 error("Failed to assume authority over key %d (%m)\n", key);
185
186         /* ask the kernel to describe the key to us */
187         if (xdebug < 2) {
188                 ret = keyctl_describe_alloc(key, &buf);
189                 if (ret < 0)
190                         goto inaccessible;
191         }
192         else {
193                 buf = strdup("user;0;0;1f0000;debug:1234");
194         }
195
196         /* extract the type and description from the key */
197         debug("Key descriptor: \"%s\"\n", buf);
198         ntype = -1;
199         dpos = -1;
200
201         n = sscanf(buf, "%*[^;]%n;%*d;%*d;%x;%n", &ntype, &n, &dpos);
202         if (n != 1)
203                 error("Failed to parse key description\n");
204
205         ktype = buf;
206         ktype[ntype] = 0;
207         kdesc = buf + dpos;
208
209         debug("Key type: %s\n", ktype);
210         debug("Key desc: %s\n", kdesc);
211
212         /* get hold of the callout info */
213         callout_info = argv[8];
214
215         if (!callout_info) {
216                 void *tmp;
217
218                 if (keyctl_read_alloc(KEY_SPEC_REQKEY_AUTH_KEY, &tmp) < 0)
219                         error("Failed to retrieve callout info (%m)\n");
220
221                 callout_info = tmp;
222         }
223
224         debug("CALLOUT: '%s'\n", callout_info);
225
226         /* determine the action to perform */
227         lookup_action(argv[1],          /* op */
228                       key,              /* ID of key under construction */
229                       ktype,            /* key type */
230                       kdesc,            /* key description */
231                       callout_info      /* call out information */
232                       );
233
234 inaccessible:
235         error("Key %d is inaccessible (%m)\n", key);
236
237 } /* end main() */
238
239 /*****************************************************************************/
240 /*
241  * determine the action to perform
242  */
243 static void lookup_action(char *op,
244                           key_serial_t key,
245                           char *ktype,
246                           char *kdesc,
247                           char *callout_info)
248 {
249         char buf[4096 + 2], *p, *q;
250         FILE *conf;
251         int len, oplen, ktlen, kdlen, cilen;
252
253         oplen = strlen(op);
254         ktlen = strlen(ktype);
255         kdlen = strlen(kdesc);
256         cilen = strlen(callout_info);
257
258         /* search the config file for a command to run */
259         conf = fopen(xdebug < 2 ? "/etc/request-key.conf" : "request-key.conf", "r");
260         if (!conf)
261                 error("Cannot open /etc/request-key.conf: %m\n");
262
263         for (confline = 1;; confline++) {
264                 /* read the file line-by-line */
265                 if (!fgets(buf, sizeof(buf), conf)) {
266                         if (feof(conf))
267                                 error("Cannot find command to construct key %d\n", key);
268                         error("Error reading /etc/request-key.conf\n");
269                 }
270
271                 len = strlen(buf);
272                 if (len >= sizeof(buf) - 2)
273                         error("/etc/request-key.conf:%d: Line too long\n", confline);
274
275                 /* ignore blank lines and comments */
276                 if (len == 1 || buf[0] == '#' || isspace(buf[0]))
277                         continue;
278
279                 buf[--len] = 0;
280                 p = buf;
281
282                 /* attempt to match the op */
283                 q = p;
284                 while (*p && !isspace(*p)) p++;
285                 if (!*p)
286                         goto syntax_error;
287                 *p = 0;
288
289                 if (!match(q, p - q, op, oplen))
290                         continue;
291
292                 p++;
293
294                 /* attempt to match the type */
295                 while (isspace(*p)) p++;
296                 if (!*p)
297                         goto syntax_error;
298
299                 q = p;
300                 while (*p && !isspace(*p)) p++;
301                 if (!*p)
302                         goto syntax_error;
303                 *p = 0;
304
305                 if (!match(q, p - q, ktype, ktlen))
306                         continue;
307
308                 p++;
309
310                 /* attempt to match the description */
311                 while (isspace(*p)) p++;
312                 if (!*p)
313                         goto syntax_error;
314
315                 q = p;
316                 while (*p && !isspace(*p)) p++;
317                 if (!*p)
318                         goto syntax_error;
319                 *p = 0;
320
321                 if (!match(q, p - q, kdesc, kdlen))
322                         continue;
323
324                 p++;
325
326                 /* attempt to match the callout info */
327                 while (isspace(*p)) p++;
328                 if (!*p)
329                         goto syntax_error;
330
331                 q = p;
332                 while (*p && !isspace(*p)) p++;
333                 if (!*p)
334                         goto syntax_error;
335                 *p = 0;
336
337                 if (!match(q, p - q, callout_info, cilen))
338                         continue;
339
340                 p++;
341
342                 debug("Line %d matches\n", confline);
343
344                 /* we've got an action */
345                 while (isspace(*p)) p++;
346                 if (!*p)
347                         goto syntax_error;
348
349                 fclose(conf);
350
351                 execute_program(op, key, ktype, kdesc, callout_info, p);
352         }
353
354         error("/etc/request-key.conf: No matching action\n");
355
356 syntax_error:
357         error("/etc/request-key.conf:%d: Syntax error\n", confline);
358
359 } /* end lookup_action() */
360
361 /*****************************************************************************/
362 /*
363  * attempt to match a datum to a pattern
364  * - one asterisk is allowed anywhere in the pattern to indicate a wildcard
365  * - returns true if matched, false if not
366  */
367 static int match(const char *pattern, int plen, const char *datum, int dlen)
368 {
369         const char *asterisk;
370         int n;
371
372         debug("match(%*.*s,%*.*s)\n", plen, plen, pattern, dlen, dlen, datum);
373
374         asterisk = memchr(pattern, '*', plen);
375         if (!asterisk) {
376                 /* exact match only if no wildcard */
377                 if (plen == dlen && memcmp(pattern, datum, dlen) == 0)
378                         goto yes;
379                 goto no;
380         }
381
382         /* the datum mustn't be shorter than the pattern without the asterisk */
383         if (dlen < plen - 1)
384                 goto no;
385
386         n = asterisk - pattern;
387         if (n == 0) {
388                 /* wildcard at beginning of pattern */
389                 pattern++;
390                 if (!*pattern)
391                         goto yes; /* "*" matches everything */
392
393                 /* match the end of the datum */
394                 plen--;
395                 if (memcmp(pattern, datum + (dlen - plen), plen) == 0)
396                         goto yes;
397                 goto no;
398         }
399
400         /* need to match beginning of datum for "abc*" and "abc*def" */
401         if (memcmp(pattern, datum, n) != 0)
402                 goto no;
403
404         if (!asterisk[1])
405                 goto yes; /* "abc*" matches */
406
407         /* match the end of the datum */
408         asterisk++;
409         n = plen - n - 1;
410         if (memcmp(pattern, datum + (dlen - n), n) == 0)
411                 goto yes;
412
413 no:
414         debug(" = no\n");
415         return 0;
416
417 yes:
418         debug(" = yes\n");
419         return 1;
420
421 } /* end match() */
422
423 /*****************************************************************************/
424 /*
425  * execute a program to deal with a key
426  */
427 static void execute_program(char *op,
428                             key_serial_t key,
429                             char *ktype,
430                             char *kdesc,
431                             char *callout_info,
432                             char *cmdline)
433 {
434         char *argv[256];
435         char *prog, *p, *q;
436         int argc, pipeit;
437
438         debug("execute_program('%s','%s')\n", callout_info, cmdline);
439
440         /* if the commandline begins with a bar, then we pipe the callout data into it and read
441          * back the payload data
442          */
443         pipeit = 0;
444
445         if (cmdline[0] == '|') {
446                 pipeit = 1;
447                 cmdline++;
448         }
449
450         /* extract the path to the program to run */
451         prog = p = cmdline;
452         while (*p && !isspace(*p)) p++;
453 //      if (!*p)
454 //              error("/etc/request-key.conf:%d: No command path\n", confline);
455 //      *p++ = 0;
456         if (*p)
457                 *p++ = 0;
458
459         argv[0] = strrchr(prog, '/') + 1;
460
461         /* extract the arguments */
462         for (argc = 1; p; argc++) {
463                 while (isspace(*p)) p++;
464                 if (!*p)
465                         break;
466
467                 if (argc >= 254)
468                         error("/etc/request-key.conf:%d: Too many arguments\n", confline);
469                 argv[argc] = q = p;
470
471                 while (*p && !isspace(*p)) p++;
472
473                 if (*p)
474                         *p++ = 0;
475                 else
476                         p = NULL;
477
478                 debug("argv[%d]: '%s'\n", argc, argv[argc]);
479
480                 if (*q != '%')
481                         continue;
482
483                 /* it's a macro */
484                 q++;
485                 if (!*q)
486                         error("/etc/request-key.conf:%d: Missing macro name\n", confline);
487
488                 if (*q == '%') {
489                         /* it's actually an anti-macro escape "%%..." -> "%..." */
490                         argv[argc]++;
491                         continue;
492                 }
493
494                 /* single character macros */
495                 if (!q[1]) {
496                         switch (*q) {
497                         case 'o': argv[argc] = op;                      continue;
498                         case 'k': argv[argc] = xkey;                    continue;
499                         case 't': argv[argc] = ktype;                   continue;
500                         case 'd': argv[argc] = kdesc;                   continue;
501                         case 'c': argv[argc] = callout_info;            continue;
502                         case 'u': argv[argc] = xuid;                    continue;
503                         case 'g': argv[argc] = xgid;                    continue;
504                         case 'T': argv[argc] = xthread_keyring;         continue;
505                         case 'P': argv[argc] = xprocess_keyring;        continue;
506                         case 'S': argv[argc] = xsession_keyring;        continue;
507                         default:
508                                 error("/etc/request-key.conf:%d: Unsupported macro\n", confline);
509                         }
510                 }
511
512                 /* keysub macro */
513                 if (*q == '{') {
514                         key_serial_t keysub;
515                         void *tmp;
516                         char *ksdesc, *end, *subdata;
517                         int ret, loop;
518
519                         /* extract type and description */
520                         q++;
521                         ksdesc = strchr(q, ':');
522                         if (!ksdesc)
523                                 error("/etc/request-key.conf:%d: Keysub macro lacks ':'\n",
524                                       confline);
525                         *ksdesc++ = 0;
526                         end = strchr(ksdesc, '}');
527                         if (!end)
528                                 error("/etc/request-key.conf:%d: Unterminated keysub macro\n",
529                                       confline);
530
531                         *end++ = 0;
532                         if (*end)
533                                 error("/etc/request-key.conf:%d:"
534                                       " Keysub macro has trailing rubbish\n",
535                                       confline);
536
537                         debug("Keysub: %s key \"%s\"\n", q, ksdesc);
538
539                         if (!q[0])
540                                 error("/etc/request-key.conf:%d: Keysub type empty\n", confline);
541
542                         if (!ksdesc[0])
543                                 error("/etc/request-key.conf:%d: Keysub description empty\n",
544                                       confline);
545
546                         /* look up the key in the requestor's keyrings, but fail immediately if the
547                          * key is not found rather than invoking /sbin/request-key again
548                          */
549                         keysub = request_key(q, ksdesc, NULL, 0);
550                         if (keysub < 0)
551                                 error("/etc/request-key.conf:%d:"
552                                       " Keysub key not found: %m\n",
553                                       confline);
554
555                         ret = keyctl_read_alloc(keysub, &tmp);
556                         if (ret < 0)
557                                 error("/etc/request-key.conf:%d:"
558                                       " Can't read keysub %d data: %m\n",
559                                       confline, keysub);
560                         subdata = tmp;
561
562                         for (loop = 0; loop < ret; loop++)
563                                 if (!isprint(subdata[loop]))
564                                         error("/etc/request-key.conf:%d:"
565                                               " keysub %d data not printable ('%02hhx')\n",
566                                               confline, keysub, subdata[loop]);
567
568                         argv[argc] = subdata;
569                         continue;
570                 }
571         }
572
573         if (argc == 0)
574                 error("/etc/request-key.conf:%d: No arguments\n", confline);
575
576         argv[argc] = NULL;
577
578         if (xdebug) {
579                 char **ap;
580
581                 debug("%s %s\n", pipeit ? "PipeThru" : "Run", prog);
582                 for (ap = argv; *ap; ap++)
583                         debug("- argv[%td] = \"%s\"\n", ap - argv, *ap);
584         }
585
586         /* become the same UID/GID as the key requesting process */
587         //setgid(atoi(xuid));
588         //setuid(atoi(xgid));
589
590         /* if the last argument is a single bar, we spawn off the program dangling on the end of
591          * three pipes and read the key material from the program, otherwise we just exec
592          */
593         if (pipeit)
594                 pipe_to_program(op, key, ktype, kdesc, callout_info, prog, argv);
595
596         /* attempt to execute the command */
597         execv(prog, argv);
598
599         error("/etc/request-key.conf:%d: Failed to execute '%s': %m\n", confline, prog);
600
601 } /* end execute_program() */
602
603 /*****************************************************************************/
604 /*
605  * pipe the callout information to the specified program and retrieve the payload data over another
606  * pipe
607  */
608 static void pipe_to_program(char *op,
609                             key_serial_t key,
610                             char *ktype,
611                             char *kdesc,
612                             char *callout_info,
613                             char *prog,
614                             char **argv)
615 {
616         char errbuf[512], payload[32768 + 1], *pp, *pc, *pe;
617         int ipi[2], opi[2], epi[2], childpid;
618         int ifl, ofl, efl, npay, ninfo, espace, tmp;
619
620         debug("pipe_to_program(%s -> %s)", callout_info, prog);
621
622         if (pipe(ipi) < 0 || pipe(opi) < 0 || pipe(epi) < 0)
623                 error("pipe failed: %m");
624
625         childpid = fork();
626         if (childpid == -1)
627                 error("fork failed: %m");
628
629         if (childpid == 0) {
630                 /* child process */
631                 if (dup2(ipi[0], 0) < 0 ||
632                     dup2(opi[1], 1) < 0 ||
633                     dup2(epi[1], 2) < 0)
634                         error("dup2 failed: %m");
635                 close(ipi[0]);
636                 close(ipi[1]);
637                 close(opi[0]);
638                 close(opi[1]);
639                 close(epi[0]);
640                 close(epi[1]);
641
642                 execv(prog, argv);
643                 error("/etc/request-key.conf:%d: Failed to execute '%s': %m\n", confline, prog);
644         }
645
646         /* parent process */
647         close(ipi[0]);
648         close(opi[1]);
649         close(epi[1]);
650
651 #define TOSTDIN ipi[1]
652 #define FROMSTDOUT opi[0]
653 #define FROMSTDERR epi[0]
654
655         ifl = fcntl(TOSTDIN, F_GETFL);
656         ofl = fcntl(FROMSTDOUT, F_GETFL);
657         efl = fcntl(FROMSTDERR, F_GETFL);
658         if (ifl < 0 || ofl < 0 || efl < 0)
659                 error("fcntl/F_GETFL failed: %m");
660
661         ifl |= O_NONBLOCK;
662         ofl |= O_NONBLOCK;
663         efl |= O_NONBLOCK;
664
665         if (fcntl(TOSTDIN, F_SETFL, ifl) < 0 ||
666             fcntl(FROMSTDOUT, F_SETFL, ofl) < 0 ||
667             fcntl(FROMSTDERR, F_SETFL, efl) < 0)
668                 error("fcntl/F_SETFL failed: %m");
669
670         ninfo = strlen(callout_info);
671         pc = callout_info;
672
673         npay = sizeof(payload);
674         pp = payload;
675
676         espace = sizeof(errbuf);
677         pe = errbuf;
678
679         do {
680                 fd_set rfds, wfds;
681
682                 FD_ZERO(&rfds);
683                 FD_ZERO(&wfds);
684
685                 if (TOSTDIN != -1) {
686                         if (ninfo > 0) {
687                                 FD_SET(TOSTDIN, &wfds);
688                         }
689                         else {
690                                 close(TOSTDIN);
691                                 TOSTDIN = -1;
692                                 continue;
693                         }
694                 }
695
696                 if (FROMSTDOUT != -1)
697                         FD_SET(FROMSTDOUT, &rfds);
698
699                 if (FROMSTDERR != -1)
700                         FD_SET(FROMSTDERR, &rfds);
701
702                 tmp = TOSTDIN > FROMSTDOUT ? TOSTDIN : FROMSTDOUT;
703                 tmp = tmp > FROMSTDERR ? tmp : FROMSTDERR;
704                 tmp++;
705
706                 debug("select r=%d,%d w=%d m=%d\n", FROMSTDOUT, FROMSTDERR, TOSTDIN, tmp);
707
708                 tmp = select(tmp, &rfds, &wfds, NULL, NULL);
709                 if (tmp < 0)
710                         error("select failed: %m\n");
711
712                 if (TOSTDIN != -1 && FD_ISSET(TOSTDIN, &wfds)) {
713                         tmp = write(TOSTDIN, pc, ninfo);
714                         if (tmp < 0) {
715                                 if (errno != EPIPE)
716                                         error("write failed: %m\n");
717
718                                 debug("EPIPE");
719                                 ninfo = 0;
720                         }
721                         else {
722                                 debug("wrote %d\n", tmp);
723
724                                 pc += tmp;
725                                 ninfo -= tmp;
726                         }
727                 }
728
729                 if (FROMSTDOUT != -1 && FD_ISSET(FROMSTDOUT, &rfds)) {
730                         tmp = read(FROMSTDOUT, pp, npay);
731                         if (tmp < 0)
732                                 error("read failed: %m\n");
733
734                         debug("read %d\n", tmp);
735
736                         if (tmp == 0) {
737                                 close(FROMSTDOUT);
738                                 FROMSTDOUT = -1;
739                         }
740                         else {
741                                 pp += tmp;
742                                 npay -= tmp;
743
744                                 if (npay == 0)
745                                         error("Too much data read from query program\n");
746                         }
747                 }
748
749                 if (FROMSTDERR != -1 && FD_ISSET(FROMSTDERR, &rfds)) {
750                         char *nl;
751
752                         tmp = read(FROMSTDERR, pe, espace);
753                         if (tmp < 0)
754                                 error("read failed: %m\n");
755
756                         debug("read err %d\n", tmp);
757
758                         if (tmp == 0) {
759                                 close(FROMSTDERR);
760                                 FROMSTDERR = -1;
761                                 continue;
762                         }
763
764                         pe += tmp;
765                         espace -= tmp;
766
767                         while ((nl = memchr(errbuf, '\n', pe - errbuf))) {
768                                 int n, rest;
769
770                                 nl++;
771                                 n = nl - errbuf;
772
773                                 if (xdebug)
774                                         fprintf(stderr, "Child: %*.*s", n, n, errbuf);
775
776                                 if (!xnolog) {
777                                         openlog("request-key", 0, LOG_AUTHPRIV);
778                                         syslog(LOG_ERR, "Child: %*.*s", n, n, errbuf);
779                                         closelog();
780                                 }
781
782                                 rest = pe - nl;
783                                 if (rest > 0) {
784                                         memmove(errbuf, nl, rest);
785                                         pe -= n;
786                                         espace += n;
787                                 }
788                                 else {
789                                         pe = errbuf;
790                                         espace = sizeof(errbuf);
791                                 }
792                         }
793
794                         if (espace == 0) {
795                                 int n = sizeof(errbuf);
796
797                                 if (xdebug)
798                                         fprintf(stderr, "Child: %*.*s", n, n, errbuf);
799
800                                 if (!xnolog) {
801                                         openlog("request-key", 0, LOG_AUTHPRIV);
802                                         syslog(LOG_ERR, "Child: %*.*s", n, n, errbuf);
803                                         closelog();
804                                 }
805
806                                 pe = errbuf;
807                                 espace = sizeof(errbuf);
808                         }
809                 }
810
811         } while (TOSTDIN != -1 || FROMSTDOUT != -1 || FROMSTDERR != -1);
812
813         /* wait for the program to exit */
814         if (waitpid(childpid, &tmp, 0) != childpid)
815                 error("wait for child failed: %m\n");
816
817         /* if the process exited non-zero or died on a signal, then we call back in to ourself to
818          * decide on negation
819          * - this is not exactly beautiful but the quickest way of having configurable negation
820          *   settings
821          */
822         if (WIFEXITED(tmp) && WEXITSTATUS(tmp) != 0) {
823                 if (norecurse)
824                         error("child exited %d\n", WEXITSTATUS(tmp));
825
826                 norecurse = 1;
827                 debug("child exited %d\n", WEXITSTATUS(tmp));
828                 lookup_action("negate", key, ktype, kdesc, callout_info);
829         }
830
831         if (WIFSIGNALED(tmp)) {
832                 if (norecurse)
833                         error("child died on signal %d\n", WTERMSIG(tmp));
834
835                 norecurse = 1;
836                 debug("child died on signal %d\n", WTERMSIG(tmp));
837                 lookup_action("negate", key, ktype, kdesc, callout_info);
838         }
839
840         /* attempt to instantiate the key */
841         debug("instantiate with %td bytes\n", pp - payload);
842
843         if (keyctl_instantiate(key, payload, pp - payload, 0) < 0)
844                 error("instantiate key failed: %m\n");
845
846         debug("instantiation successful\n");
847         exit(0);
848
849 } /* end pipe_to_program() */