8d6c74e89356cba5cb0c835756590e9063096161
[dragonfly.git] / usr.sbin / pkg_install / sign / pgp_check.c
1 /* $OpenBSD: pgp_check.c,v 1.2 1999/10/07 16:30:32 espie Exp $ */
2 /*-
3  * Copyright (c) 1999 Marc Espie.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by Marc Espie for the OpenBSD
16  * Project.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS 
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
21  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OPENBSD
22  * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  * $FreeBSD: src/usr.sbin/pkg_install/sign/pgp_check.c,v 1.1.2.2 2002/08/20 06:35:08 obrien Exp $
31  * $DragonFly: src/usr.sbin/pkg_install/sign/Attic/pgp_check.c,v 1.2 2003/06/17 04:29:59 dillon Exp $
32  */
33
34 #include <stdio.h>
35 #include <errno.h>
36 #include <assert.h>
37 #include <unistd.h>
38 #include <fcntl.h>
39 #include <paths.h>
40 #include <stdlib.h>
41 #include <sys/stat.h>
42 #include "stand.h"
43 #include "pgp.h"
44 #include "gzip.h"
45 #include "extern.h"
46
47 #ifndef _PATH_DEVNULL
48 #define _PATH_DEVNULL   "/dev/null"
49 #endif
50
51 /* transform current process into pgp signature checker -u userid <fd */
52 static void 
53 pgpcheck(fd, userid, envp) 
54         int fd;
55         const char *userid;
56         char *envp[];
57 {
58         int fdnull;
59         pchar argv[6];
60         int argc = 0;
61
62         argv[argc++] = PGP;
63         argv[argc++] = "+batchmode";
64         argv[argc++] = "-f";
65
66         if (userid) {
67                 argv[argc++] = "-u";
68                 argv[argc++] = (char *)userid;
69         }
70         argv[argc++] = NULL;
71
72         assert(argc <= sizeof argv / sizeof(pchar));
73
74         fdnull = open(_PATH_DEVNULL, O_RDWR);
75         if (fdnull == -1 ||
76             dup2(fd, fileno(stdin)) == -1 || 
77             dup2(fdnull, fileno(stdout)) == -1 ||
78                  close(fdnull) == -1 || close(fd) == -1 ||
79             execve(PGP, argv, envp)  == -1)
80                  perror("launching pgp");
81                 exit(errno);
82 }
83
84 struct pgp_checker {
85         pid_t id;
86         int fdout;
87         int status;
88 #ifdef DEBUG_DUMP
89         FILE *out;
90 #endif
91 };
92
93 void *
94 new_pgp_checker(h, sign, userid, envp, filename)
95         struct mygzip_header *h;
96         struct signature *sign;
97         const char *userid;     
98         char *envp[];
99         /*@observer@*/const char *filename;
100 {
101         struct pgp_checker *n;
102         int topgpcheck[2];
103
104         assert(sign->type == TAG_PGP);
105         n = malloc(sizeof *n);
106
107         {
108                 struct stat sbuf;
109
110                 if (stat(PGP, &sbuf) == -1) {
111                         warnx("%s does not exist", PGP);
112                         return NULL;
113                 }
114         }
115         if (n == NULL) {
116                 warnx("Can't allocate pgp_checker");
117                 return NULL;
118         }
119
120         if (pipe(topgpcheck) == -1) {
121                 warn("Pgp checker pipe");
122                 free(n);
123                 return NULL;
124         }
125         switch(n->id = fork()) {
126         case -1:
127                 warn("Pgp checker process");
128                 free(n);
129                 return NULL;
130         case 0:
131                 if (close(topgpcheck[1]) == -1)
132                         exit(errno);
133                 pgpcheck(topgpcheck[0], userid, envp);
134                 /*@notreached@*/
135                 break;
136         default:
137                 (void)close(topgpcheck[0]);
138                 break;
139         }
140         n->fdout = topgpcheck[1];
141                 /* so that subsequent fork() won't duplicate it inadvertently */
142         (void)fcntl(n->fdout, F_SETFD, FD_CLOEXEC);     
143 #ifdef DEBUG_DUMP
144         n->out = fopen("compare", "w");
145 #endif
146         n->status = PKG_GOODSIG;
147
148         pgp_add(n, sign->data, sign->length);
149         if (gzip_copy_header(h, sign->next, pgp_add, n) == 0) {
150                 warnx("Unexpected header in %s", filename);
151                 n->status = PKG_SIGERROR;
152         }
153         return n;
154 }
155         
156 void 
157 pgp_add(arg, buffer, length)
158         void *arg;
159         const char *buffer;
160         size_t length;
161 {
162         struct pgp_checker *n = arg;
163
164         if (n->status == PKG_GOODSIG) {
165 #ifdef DEBUG_DUMP
166         fwrite(buffer, 1, length, n->out);
167 #endif
168                 while (length > 0) {
169                         ssize_t l = write(n->fdout, buffer, length);
170                         if (l == -1) {
171                                 n->status = PKG_SIGERROR;
172                                 break;
173                         }
174                         length -= l;
175                         buffer += l;
176                 }
177         }
178 }
179
180 int
181 pgp_sign_ok(arg)
182         void *arg;
183 {
184         struct pgp_checker *n = arg;
185         int status = n->status;
186
187 #ifdef DEBUG_DUMP
188         fclose(n->out);
189 #endif
190         if (close(n->fdout) != 0)
191                 status = PKG_SIGERROR;
192         if (reap(n->id) != 0)
193                 status = PKG_BADSIG;
194         free(n);
195         return status;
196 }