Many: use srelax() is some places
[s-mailx.git] / ssl.c
blob0bc3a02a72c3572faf4782cf51201656c85e3a6d
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 - 2013 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 #include "config.h"
42 #ifndef HAVE_SSL
43 typedef int avoid_empty_file_compiler_warning;
44 #else
45 #include "nail.h"
47 void
48 ssl_set_vrfy_level(const char *uhp)
50 size_t l;
51 char *cp, *vrvar;
53 ssl_vrfy_level = VRFY_ASK;
54 l = strlen(uhp);
55 vrvar = ac_alloc(l + 12);
56 memcpy(vrvar, "ssl-verify-", 11);
57 memcpy(vrvar + 11, uhp, l + 1);
59 if ((cp = value(vrvar)) == NULL)
60 cp = value("ssl-verify");
61 ac_free(vrvar);
62 if (cp != NULL) {
63 if (strcmp(cp, "strict") == 0)
64 ssl_vrfy_level = VRFY_STRICT;
65 else if (strcmp(cp, "ask") == 0)
66 ssl_vrfy_level = VRFY_ASK;
67 else if (strcmp(cp, "warn") == 0)
68 ssl_vrfy_level = VRFY_WARN;
69 else if (strcmp(cp, "ignore") == 0)
70 ssl_vrfy_level = VRFY_IGNORE;
71 else
72 fprintf(stderr, tr(265,
73 "invalid value of ssl-verify: %s\n"), cp);
77 enum okay
78 ssl_vrfy_decide(void)
80 enum okay ok = STOP;
82 switch (ssl_vrfy_level) {
83 case VRFY_STRICT:
84 ok = STOP;
85 break;
86 case VRFY_ASK:
88 char *line = NULL;
89 size_t linesize = 0;
91 fprintf(stderr, tr(264, "Continue (y/n)? "));
92 if (readline_restart(stdin, &line, &linesize, 0) > 0 &&
93 *line == 'y')
94 ok = OKAY;
95 else
96 ok = STOP;
97 if (line)
98 free(line);
100 break;
101 case VRFY_WARN:
102 case VRFY_IGNORE:
103 ok = OKAY;
105 return ok;
108 char *
109 ssl_method_string(const char *uhp)
111 size_t l;
112 char *cp, *mtvar;
114 l = strlen(uhp);
115 mtvar = ac_alloc(l + 12);
116 memcpy(mtvar, "ssl-method-", 11);
117 memcpy(mtvar + 11, uhp, l + 1);
118 if ((cp = value(mtvar)) == NULL)
119 cp = value("ssl-method");
120 ac_free(mtvar);
121 return cp;
124 enum okay
125 smime_split(FILE *ip, FILE **hp, FILE **bp, long xcount, int keep)
127 /* TODO like i said quite often now, the entire SSL stuff really needs
128 * TODO a review ASAP; also in respect to correct resource release, and
129 * TODO especially in case of errors; S-nail is a program that REALLY
130 * TODO may run for a week or longer!!! */
131 char *buf, *hn, *bn;
132 char *savedfields = NULL;
133 size_t bufsize, buflen, cnt, savedsize = 0;
134 int c;
136 if ((*hp = Ftemp(&hn, "Rh", "w+", 0600, 1)) == NULL)
137 goto jetmp;
138 rm(hn);
139 Ftfree(&hn);
140 if ((*bp = Ftemp(&bn, "Rb", "w+", 0600, 1)) == NULL) {
141 jetmp:
142 perror("tempfile");
143 return STOP;
145 rm(bn);
146 Ftfree(&bn);
148 buf = smalloc(bufsize = LINESIZE);
149 savedfields = smalloc(savedsize = 1);
150 *savedfields = '\0';
151 if (xcount < 0)
152 cnt = fsize(ip);
153 else
154 cnt = xcount;
156 while (fgetline(&buf, &bufsize, &cnt, &buflen, ip, 0) != NULL &&
157 *buf != '\n') {
158 if (ascncasecmp(buf, "content-", 8) == 0) {
159 if (keep)
160 fputs("X-Encoded-", *hp);
161 for (;;) {
162 savedsize += buflen;
163 savedfields = srealloc(savedfields, savedsize);
164 memcpy(savedfields + strlen(savedfields),
165 buf, strlen(buf));
166 if (keep)
167 fwrite(buf, sizeof *buf, buflen, *hp);
168 c = getc(ip);
169 ungetc(c, ip);
170 if (!blankchar(c))
171 break;
172 fgetline(&buf, &bufsize, &cnt, &buflen,
173 ip, 0);
175 continue;
177 fwrite(buf, sizeof *buf, buflen, *hp);
179 fflush(*hp);
180 rewind(*hp);
182 fputs(savedfields, *bp);
183 putc('\n', *bp);
184 while (fgetline(&buf, &bufsize, &cnt, &buflen, ip, 0) != NULL)
185 fwrite(buf, sizeof *buf, buflen, *bp);
186 fflush(*bp);
187 rewind(*bp);
189 free(savedfields);
190 free(buf);
191 return OKAY;
194 FILE *
195 smime_sign_assemble(FILE *hp, FILE *bp, FILE *sp)
197 char *boundary, *cp;
198 FILE *op;
199 int c, lastc = EOF;
201 if ((op = Ftemp(&cp, "Rs", "w+", 0600, 1)) == NULL) {
202 perror("tempfile");
203 return NULL;
205 rm(cp);
206 Ftfree(&cp);
207 boundary = mime_create_boundary();
208 while ((c = getc(hp)) != EOF) {
209 if (c == '\n' && lastc == '\n')
210 break;
211 putc(c, op);
212 lastc = c;
214 fprintf(op, "Content-Type: multipart/signed;\n"
215 " protocol=\"application/x-pkcs7-signature\"; micalg=sha1;\n"
216 " boundary=\"%s\"\n\n", boundary);
217 fprintf(op, "This is an S/MIME signed message.\n\n--%s\n",
218 boundary);
219 while ((c = getc(bp)) != EOF)
220 putc(c, op);
221 fprintf(op, "\n--%s\n", boundary);
222 fputs("Content-Type: application/x-pkcs7-signature; "
223 "name=\"smime.p7s\"\n"
224 "Content-Transfer-Encoding: base64\n"
225 "Content-Disposition: attachment; filename=\"smime.p7s\"\n\n",
226 op);
227 while ((c = getc(sp)) != EOF) {
228 if (c == '-') {
229 while ((c = getc(sp)) != EOF && c != '\n');
230 continue;
232 putc(c, op);
234 fprintf(op, "\n--%s--\n", boundary);
235 Fclose(hp);
236 Fclose(bp);
237 Fclose(sp);
238 fflush(op);
239 if (ferror(op)) {
240 perror("signed output data");
241 Fclose(op);
242 return NULL;
244 rewind(op);
245 return op;
248 FILE *
249 smime_encrypt_assemble(FILE *hp, FILE *yp)
251 char *cp;
252 FILE *op;
253 int c, lastc = EOF;
255 if ((op = Ftemp(&cp, "Rs", "w+", 0600, 1)) == NULL) {
256 perror("tempfile");
257 return NULL;
259 rm(cp);
260 Ftfree(&cp);
261 while ((c = getc(hp)) != EOF) {
262 if (c == '\n' && lastc == '\n')
263 break;
264 putc(c, op);
265 lastc = c;
267 fprintf(op, "Content-Type: application/x-pkcs7-mime; "
268 "name=\"smime.p7m\"\n"
269 "Content-Transfer-Encoding: base64\n"
270 "Content-Disposition: attachment; "
271 "filename=\"smime.p7m\"\n\n");
272 while ((c = getc(yp)) != EOF) {
273 if (c == '-') {
274 while ((c = getc(yp)) != EOF && c != '\n');
275 continue;
277 putc(c, op);
279 Fclose(hp);
280 Fclose(yp);
281 fflush(op);
282 if (ferror(op)) {
283 perror("encrypted output data");
284 Fclose(op);
285 return NULL;
287 rewind(op);
288 return op;
291 struct message *
292 smime_decrypt_assemble(struct message *m, FILE *hp, FILE *bp)
294 ui32_t lastnl = 0;
295 int binary = 0;
296 char *buf = NULL;
297 size_t bufsize = 0, buflen, cnt;
298 long lines = 0, octets = 0;
299 struct message *x;
300 off_t offset;
302 x = salloc(sizeof *x);
303 *x = *m;
304 fflush(mb.mb_otf);
305 fseek(mb.mb_otf, 0L, SEEK_END);
306 offset = ftell(mb.mb_otf);
307 cnt = fsize(hp);
308 while (fgetline(&buf, &bufsize, &cnt, &buflen, hp, 0) != NULL) {
309 char const *cp;
310 if (buf[0] == '\n')
311 break;
312 if ((cp = thisfield(buf, "content-transfer-encoding")) != NULL)
313 if (ascncasecmp(cp, "binary", 7) == 0)
314 binary = 1;
315 fwrite(buf, sizeof *buf, buflen, mb.mb_otf);
316 octets += buflen;
317 lines++;
319 octets += mkdate(mb.mb_otf, "X-Decoding-Date");
320 lines++;
321 cnt = fsize(bp);
322 while (fgetline(&buf, &bufsize, &cnt, &buflen, bp, 0) != NULL) {
323 lines++;
324 if (!binary && buf[buflen-1] == '\n' && buf[buflen-2] == '\r')
325 buf[--buflen-1] = '\n';
326 fwrite(buf, sizeof *buf, buflen, mb.mb_otf);
327 octets += buflen;
328 if (buf[0] == '\n')
329 lastnl++;
330 else if (buf[buflen-1] == '\n')
331 lastnl = 1;
332 else
333 lastnl = 0;
335 while (!binary && lastnl < 2) {
336 putc('\n', mb.mb_otf);
337 lines++;
338 octets++;
339 lastnl++;
341 Fclose(hp);
342 Fclose(bp);
343 free(buf);
344 fflush(mb.mb_otf);
345 if (ferror(mb.mb_otf)) {
346 perror("decrypted output data");
347 return NULL;
349 x->m_size = x->m_xsize = octets;
350 x->m_lines = x->m_xlines = lines;
351 x->m_block = mailx_blockof(offset);
352 x->m_offset = mailx_offsetof(offset);
353 return x;
356 int
357 ccertsave(void *v)
359 int *ip;
360 int f, *msgvec;
361 char *file = NULL, *str = v;
362 int val = 0;
363 FILE *fp;
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 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 */