cc-test.sh: fix for UnixWare 7.1.4 awk(1)
[s-mailx.git] / ssl.c
blobc840651c5e5c289ba904f54006c40da97f268bb3
1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ Generic SSL / SMIME commands.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2014 Steffen "Daode" Nurpmeso <sdaoden@users.sf.net>.
6 */
7 /*
8 * Copyright (c) 2002
9 * Gunnar Ritter. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by Gunnar Ritter
22 * and his contributors.
23 * 4. Neither the name of Gunnar Ritter nor the names of his contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
40 #ifndef HAVE_AMALGAMATION
41 # include "nail.h"
42 #endif
44 EMPTY_FILE(ssl)
45 #ifdef HAVE_SSL
46 FL void
47 ssl_set_vrfy_level(const char *uhp)
49 size_t l;
50 char *cp, *vrvar;
52 ssl_vrfy_level = VRFY_ASK;
53 l = strlen(uhp);
54 vrvar = ac_alloc(l + 12);
55 memcpy(vrvar, "ssl-verify-", 11);
56 memcpy(vrvar + 11, uhp, l + 1);
58 if ((cp = vok_vlook(vrvar)) == NULL)
59 cp = ok_vlook(ssl_verify);
60 ac_free(vrvar);
61 if (cp != NULL) {
62 if (strcmp(cp, "strict") == 0)
63 ssl_vrfy_level = VRFY_STRICT;
64 else if (strcmp(cp, "ask") == 0)
65 ssl_vrfy_level = VRFY_ASK;
66 else if (strcmp(cp, "warn") == 0)
67 ssl_vrfy_level = VRFY_WARN;
68 else if (strcmp(cp, "ignore") == 0)
69 ssl_vrfy_level = VRFY_IGNORE;
70 else
71 fprintf(stderr, tr(265,
72 "invalid value of ssl-verify: %s\n"), cp);
76 FL enum okay
77 ssl_vrfy_decide(void)
79 enum okay ok = STOP;
81 switch (ssl_vrfy_level) {
82 case VRFY_STRICT:
83 ok = STOP;
84 break;
85 case VRFY_ASK:
87 char *line = NULL;
88 size_t linesize = 0;
90 fprintf(stderr, tr(264, "Continue (y/n)? "));
91 if (readline_restart(stdin, &line, &linesize, 0) > 0 &&
92 *line == 'y')
93 ok = OKAY;
94 else
95 ok = STOP;
96 if (line)
97 free(line);
99 break;
100 case VRFY_WARN:
101 case VRFY_IGNORE:
102 ok = OKAY;
104 return ok;
107 FL char *
108 ssl_method_string(const char *uhp)
110 size_t l;
111 char *cp, *mtvar;
113 l = strlen(uhp);
114 mtvar = ac_alloc(l + 12);
115 memcpy(mtvar, "ssl-method-", 11);
116 memcpy(mtvar + 11, uhp, l + 1);
117 if ((cp = vok_vlook(mtvar)) == NULL)
118 cp = ok_vlook(ssl_method);
119 ac_free(mtvar);
120 return cp;
123 FL enum okay
124 smime_split(FILE *ip, FILE **hp, FILE **bp, long xcount, int keep)
126 /* TODO like i said quite often now, the entire SSL stuff really needs
127 * TODO a review ASAP; also in respect to correct resource release, and
128 * TODO especially in case of errors; S-nail is a program that REALLY
129 * TODO may run for a week or longer!!! */
130 char *buf, *hn, *bn;
131 char *savedfields = NULL;
132 size_t bufsize, buflen, cnt, savedsize = 0;
133 int c;
135 if ((*hp = Ftemp(&hn, "Rh", "w+", 0600, 1)) == NULL)
136 goto jetmp;
137 rm(hn);
138 Ftfree(&hn);
139 if ((*bp = Ftemp(&bn, "Rb", "w+", 0600, 1)) == NULL) {
140 jetmp:
141 perror("tempfile");
142 return STOP;
144 rm(bn);
145 Ftfree(&bn);
147 buf = smalloc(bufsize = LINESIZE);
148 savedfields = smalloc(savedsize = 1);
149 *savedfields = '\0';
150 if (xcount < 0)
151 cnt = fsize(ip);
152 else
153 cnt = xcount;
155 while (fgetline(&buf, &bufsize, &cnt, &buflen, ip, 0) != NULL &&
156 *buf != '\n') {
157 if (ascncasecmp(buf, "content-", 8) == 0) {
158 if (keep)
159 fputs("X-Encoded-", *hp);
160 for (;;) {
161 savedsize += buflen;
162 savedfields = srealloc(savedfields, savedsize);
163 memcpy(savedfields + strlen(savedfields),
164 buf, strlen(buf));
165 if (keep)
166 fwrite(buf, sizeof *buf, buflen, *hp);
167 c = getc(ip);
168 ungetc(c, ip);
169 if (!blankchar(c))
170 break;
171 fgetline(&buf, &bufsize, &cnt, &buflen,
172 ip, 0);
174 continue;
176 fwrite(buf, sizeof *buf, buflen, *hp);
178 fflush(*hp);
179 rewind(*hp);
181 fputs(savedfields, *bp);
182 putc('\n', *bp);
183 while (fgetline(&buf, &bufsize, &cnt, &buflen, ip, 0) != NULL)
184 fwrite(buf, sizeof *buf, buflen, *bp);
185 fflush(*bp);
186 rewind(*bp);
188 free(savedfields);
189 free(buf);
190 return OKAY;
193 FL FILE *
194 smime_sign_assemble(FILE *hp, FILE *bp, FILE *sp)
196 char *boundary, *cp;
197 FILE *op;
198 int c, lastc = EOF;
200 if ((op = Ftemp(&cp, "Rs", "w+", 0600, 1)) == NULL) {
201 perror("tempfile");
202 return NULL;
204 rm(cp);
205 Ftfree(&cp);
206 boundary = mime_create_boundary();
207 while ((c = getc(hp)) != EOF) {
208 if (c == '\n' && lastc == '\n')
209 break;
210 putc(c, op);
211 lastc = c;
213 fprintf(op, "Content-Type: multipart/signed;\n"
214 " protocol=\"application/x-pkcs7-signature\"; micalg=sha1;\n"
215 " boundary=\"%s\"\n\n", boundary);
216 fprintf(op, "This is an S/MIME signed message.\n\n--%s\n",
217 boundary);
218 while ((c = getc(bp)) != EOF)
219 putc(c, op);
220 fprintf(op, "\n--%s\n", boundary);
221 fputs("Content-Type: application/x-pkcs7-signature; "
222 "name=\"smime.p7s\"\n"
223 "Content-Transfer-Encoding: base64\n"
224 "Content-Disposition: attachment; filename=\"smime.p7s\"\n\n",
225 op);
226 while ((c = getc(sp)) != EOF) {
227 if (c == '-') {
228 while ((c = getc(sp)) != EOF && c != '\n');
229 continue;
231 putc(c, op);
233 fprintf(op, "\n--%s--\n", boundary);
234 Fclose(hp);
235 Fclose(bp);
236 Fclose(sp);
237 fflush(op);
238 if (ferror(op)) {
239 perror("signed output data");
240 Fclose(op);
241 return NULL;
243 rewind(op);
244 return op;
247 FL FILE *
248 smime_encrypt_assemble(FILE *hp, FILE *yp)
250 char *cp;
251 FILE *op;
252 int c, lastc = EOF;
254 if ((op = Ftemp(&cp, "Rs", "w+", 0600, 1)) == NULL) {
255 perror("tempfile");
256 return NULL;
258 rm(cp);
259 Ftfree(&cp);
260 while ((c = getc(hp)) != EOF) {
261 if (c == '\n' && lastc == '\n')
262 break;
263 putc(c, op);
264 lastc = c;
266 fprintf(op, "Content-Type: application/x-pkcs7-mime; "
267 "name=\"smime.p7m\"\n"
268 "Content-Transfer-Encoding: base64\n"
269 "Content-Disposition: attachment; "
270 "filename=\"smime.p7m\"\n\n");
271 while ((c = getc(yp)) != EOF) {
272 if (c == '-') {
273 while ((c = getc(yp)) != EOF && c != '\n');
274 continue;
276 putc(c, op);
278 Fclose(hp);
279 Fclose(yp);
280 fflush(op);
281 if (ferror(op)) {
282 perror("encrypted output data");
283 Fclose(op);
284 return NULL;
286 rewind(op);
287 return op;
290 FL struct message *
291 smime_decrypt_assemble(struct message *m, FILE *hp, FILE *bp)
293 ui32_t lastnl = 0;
294 int binary = 0;
295 char *buf = NULL;
296 size_t bufsize = 0, buflen, cnt;
297 long lines = 0, octets = 0;
298 struct message *x;
299 off_t offset;
301 x = salloc(sizeof *x);
302 *x = *m;
303 fflush(mb.mb_otf);
304 fseek(mb.mb_otf, 0L, SEEK_END);
305 offset = ftell(mb.mb_otf);
306 cnt = fsize(hp);
307 while (fgetline(&buf, &bufsize, &cnt, &buflen, hp, 0) != NULL) {
308 char const *cp;
309 if (buf[0] == '\n')
310 break;
311 if ((cp = thisfield(buf, "content-transfer-encoding")) != NULL)
312 if (ascncasecmp(cp, "binary", 7) == 0)
313 binary = 1;
314 fwrite(buf, sizeof *buf, buflen, mb.mb_otf);
315 octets += buflen;
316 lines++;
318 octets += mkdate(mb.mb_otf, "X-Decoding-Date");
319 lines++;
320 cnt = fsize(bp);
321 while (fgetline(&buf, &bufsize, &cnt, &buflen, bp, 0) != NULL) {
322 lines++;
323 if (!binary && buf[buflen-1] == '\n' && buf[buflen-2] == '\r')
324 buf[--buflen-1] = '\n';
325 fwrite(buf, sizeof *buf, buflen, mb.mb_otf);
326 octets += buflen;
327 if (buf[0] == '\n')
328 lastnl++;
329 else if (buf[buflen-1] == '\n')
330 lastnl = 1;
331 else
332 lastnl = 0;
334 while (!binary && lastnl < 2) {
335 putc('\n', mb.mb_otf);
336 lines++;
337 octets++;
338 lastnl++;
340 Fclose(hp);
341 Fclose(bp);
342 free(buf);
343 fflush(mb.mb_otf);
344 if (ferror(mb.mb_otf)) {
345 perror("decrypted output data");
346 return NULL;
348 x->m_size = x->m_xsize = octets;
349 x->m_lines = x->m_xlines = lines;
350 x->m_block = mailx_blockof(offset);
351 x->m_offset = mailx_offsetof(offset);
352 return x;
355 FL int
356 ccertsave(void *v)
358 int *ip;
359 int *msgvec;
360 char *file = NULL, *str = v;
361 int val = 0;
362 FILE *fp;
363 bool_t f;
365 msgvec = salloc((msgCount + 2) * sizeof *msgvec);
366 if ((file = laststring(str, &f, 1)) == NULL) {
367 fprintf(stderr, "No file to save certificate given.\n");
368 return 1;
370 if (!f) {
371 *msgvec = first(0, MMNORM);
372 if (*msgvec == 0) {
373 if (inhook)
374 return 0;
375 fprintf(stderr,
376 "No messages to get certificates from.\n");
377 return 1;
379 msgvec[1] = 0;
380 } else if (getmsglist(str, msgvec, 0) < 0)
381 return 1;
382 if (*msgvec == 0) {
383 if (inhook)
384 return 0;
385 fprintf(stderr, "No applicable messages.\n");
386 return 1;
388 if ((fp = Fopen(file, "a")) == NULL) {
389 perror(file);
390 return 1;
392 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++)
393 if (smime_certsave(&message[*ip-1], *ip, fp) != OKAY)
394 val = 1;
395 Fclose(fp);
396 if (val == 0)
397 printf("Certificate(s) saved.\n");
398 return val;
401 FL enum okay
402 rfc2595_hostname_match(const char *host, const char *pattern)
404 if (pattern[0] == '*' && pattern[1] == '.') {
405 pattern++;
406 while (*host && *host != '.')
407 host++;
409 return asccasecmp(host, pattern) == 0 ? OKAY : STOP;
411 #endif /* HAVE_SSL */