Nits for silencing -Wshadow
[s-mailx.git] / ssl.c
bloba2592774647255add3869fa40bb5e66c04129327
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 "rcv.h"
46 #include "extern.h"
48 void
49 ssl_set_vrfy_level(const char *uhp)
51 size_t l;
52 char *cp, *vrvar;
54 ssl_vrfy_level = VRFY_ASK;
55 l = strlen(uhp);
56 vrvar = ac_alloc(l + 12);
57 memcpy(vrvar, "ssl-verify-", 11);
58 memcpy(vrvar + 11, uhp, l + 1);
60 if ((cp = value(vrvar)) == NULL)
61 cp = value("ssl-verify");
62 ac_free(vrvar);
63 if (cp != NULL) {
64 if (strcmp(cp, "strict") == 0)
65 ssl_vrfy_level = VRFY_STRICT;
66 else if (strcmp(cp, "ask") == 0)
67 ssl_vrfy_level = VRFY_ASK;
68 else if (strcmp(cp, "warn") == 0)
69 ssl_vrfy_level = VRFY_WARN;
70 else if (strcmp(cp, "ignore") == 0)
71 ssl_vrfy_level = VRFY_IGNORE;
72 else
73 fprintf(stderr, tr(265,
74 "invalid value of ssl-verify: %s\n"), cp);
78 enum okay
79 ssl_vrfy_decide(void)
81 enum okay ok = STOP;
83 switch (ssl_vrfy_level) {
84 case VRFY_STRICT:
85 ok = STOP;
86 break;
87 case VRFY_ASK:
89 char *line = NULL;
90 size_t linesize = 0;
92 fprintf(stderr, catgets(catd, CATSET, 264,
93 "Continue (y/n)? "));
94 if (readline_restart(stdin, &line, &linesize, 0) > 0 &&
95 *line == 'y')
96 ok = OKAY;
97 else
98 ok = STOP;
99 if (line)
100 free(line);
102 break;
103 case VRFY_WARN:
104 case VRFY_IGNORE:
105 ok = OKAY;
107 return ok;
110 char *
111 ssl_method_string(const char *uhp)
113 size_t l;
114 char *cp, *mtvar;
116 l = strlen(uhp);
117 mtvar = ac_alloc(l + 12);
118 memcpy(mtvar, "ssl-method-", 11);
119 memcpy(mtvar + 11, uhp, l + 1);
120 if ((cp = value(mtvar)) == NULL)
121 cp = value("ssl-method");
122 ac_free(mtvar);
123 return cp;
126 enum okay
127 smime_split(FILE *ip, FILE **hp, FILE **bp, long xcount, int keep)
129 /* TODO like i said quite often now, the entire SSL stuff really needs
130 * TODO a review ASAP; also in respect to correct resource release, and
131 * TODO especially in case of errors; S-nail is a program that REALLY
132 * TODO may run for a week or longer!!! */
133 char *buf, *hn, *bn;
134 char *savedfields = NULL;
135 size_t bufsize, buflen, cnt, savedsize = 0;
136 int c;
138 if ((*hp = Ftemp(&hn, "Rh", "w+", 0600, 1)) == NULL)
139 goto jetmp;
140 rm(hn);
141 Ftfree(&hn);
142 if ((*bp = Ftemp(&bn, "Rb", "w+", 0600, 1)) == NULL) {
143 jetmp:
144 perror("tempfile");
145 return STOP;
147 rm(bn);
148 Ftfree(&bn);
150 buf = smalloc(bufsize = LINESIZE);
151 savedfields = smalloc(savedsize = 1);
152 *savedfields = '\0';
153 if (xcount < 0)
154 cnt = fsize(ip);
155 else
156 cnt = xcount;
158 while (fgetline(&buf, &bufsize, &cnt, &buflen, ip, 0) != NULL &&
159 *buf != '\n') {
160 if (ascncasecmp(buf, "content-", 8) == 0) {
161 if (keep)
162 fputs("X-Encoded-", *hp);
163 for (;;) {
164 savedsize += buflen;
165 savedfields = srealloc(savedfields, savedsize);
166 memcpy(savedfields + strlen(savedfields),
167 buf, strlen(buf));
168 if (keep)
169 fwrite(buf, sizeof *buf, buflen, *hp);
170 c = getc(ip);
171 ungetc(c, ip);
172 if (!blankchar(c))
173 break;
174 fgetline(&buf, &bufsize, &cnt, &buflen,
175 ip, 0);
177 continue;
179 fwrite(buf, sizeof *buf, buflen, *hp);
181 fflush(*hp);
182 rewind(*hp);
184 fputs(savedfields, *bp);
185 putc('\n', *bp);
186 while (fgetline(&buf, &bufsize, &cnt, &buflen, ip, 0) != NULL)
187 fwrite(buf, sizeof *buf, buflen, *bp);
188 fflush(*bp);
189 rewind(*bp);
191 free(savedfields);
192 free(buf);
193 return OKAY;
196 FILE *
197 smime_sign_assemble(FILE *hp, FILE *bp, FILE *sp)
199 char *boundary, *cp;
200 FILE *op;
201 int c, lastc = EOF;
203 if ((op = Ftemp(&cp, "Rs", "w+", 0600, 1)) == NULL) {
204 perror("tempfile");
205 return NULL;
207 rm(cp);
208 Ftfree(&cp);
209 boundary = mime_create_boundary();
210 while ((c = getc(hp)) != EOF) {
211 if (c == '\n' && lastc == '\n')
212 break;
213 putc(c, op);
214 lastc = c;
216 fprintf(op, "Content-Type: multipart/signed;\n"
217 " protocol=\"application/x-pkcs7-signature\"; micalg=sha1;\n"
218 " boundary=\"%s\"\n\n", boundary);
219 fprintf(op, "This is an S/MIME signed message.\n\n--%s\n",
220 boundary);
221 while ((c = getc(bp)) != EOF)
222 putc(c, op);
223 fprintf(op, "\n--%s\n", boundary);
224 fputs("Content-Type: application/x-pkcs7-signature; "
225 "name=\"smime.p7s\"\n"
226 "Content-Transfer-Encoding: base64\n"
227 "Content-Disposition: attachment; filename=\"smime.p7s\"\n\n",
228 op);
229 while ((c = getc(sp)) != EOF) {
230 if (c == '-') {
231 while ((c = getc(sp)) != EOF && c != '\n');
232 continue;
234 putc(c, op);
236 fprintf(op, "\n--%s--\n", boundary);
237 Fclose(hp);
238 Fclose(bp);
239 Fclose(sp);
240 fflush(op);
241 if (ferror(op)) {
242 perror("signed output data");
243 Fclose(op);
244 return NULL;
246 rewind(op);
247 return op;
250 FILE *
251 smime_encrypt_assemble(FILE *hp, FILE *yp)
253 char *cp;
254 FILE *op;
255 int c, lastc = EOF;
257 if ((op = Ftemp(&cp, "Rs", "w+", 0600, 1)) == NULL) {
258 perror("tempfile");
259 return NULL;
261 rm(cp);
262 Ftfree(&cp);
263 while ((c = getc(hp)) != EOF) {
264 if (c == '\n' && lastc == '\n')
265 break;
266 putc(c, op);
267 lastc = c;
269 fprintf(op, "Content-Type: application/x-pkcs7-mime; "
270 "name=\"smime.p7m\"\n"
271 "Content-Transfer-Encoding: base64\n"
272 "Content-Disposition: attachment; "
273 "filename=\"smime.p7m\"\n\n");
274 while ((c = getc(yp)) != EOF) {
275 if (c == '-') {
276 while ((c = getc(yp)) != EOF && c != '\n');
277 continue;
279 putc(c, op);
281 Fclose(hp);
282 Fclose(yp);
283 fflush(op);
284 if (ferror(op)) {
285 perror("encrypted output data");
286 Fclose(op);
287 return NULL;
289 rewind(op);
290 return op;
293 struct message *
294 smime_decrypt_assemble(struct message *m, FILE *hp, FILE *bp)
296 int binary = 0, lastnl = 0;
297 char *buf = NULL;
298 size_t bufsize = 0, buflen, cnt;
299 long lines = 0, octets = 0;
300 struct message *x;
301 off_t offset;
303 x = salloc(sizeof *x);
304 *x = *m;
305 fflush(mb.mb_otf);
306 fseek(mb.mb_otf, 0L, SEEK_END);
307 offset = ftell(mb.mb_otf);
308 cnt = fsize(hp);
309 while (fgetline(&buf, &bufsize, &cnt, &buflen, hp, 0) != NULL) {
310 char const *cp;
311 if (buf[0] == '\n')
312 break;
313 if ((cp = thisfield(buf, "content-transfer-encoding")) != NULL)
314 if (ascncasecmp(cp, "binary", 7) == 0)
315 binary = 1;
316 fwrite(buf, sizeof *buf, buflen, mb.mb_otf);
317 octets += buflen;
318 lines++;
320 octets += mkdate(mb.mb_otf, "X-Decoding-Date");
321 lines++;
322 cnt = fsize(bp);
323 while (fgetline(&buf, &bufsize, &cnt, &buflen, bp, 0) != NULL) {
324 lines++;
325 if (!binary && buf[buflen-1] == '\n' && buf[buflen-2] == '\r')
326 buf[--buflen-1] = '\n';
327 fwrite(buf, sizeof *buf, buflen, mb.mb_otf);
328 octets += buflen;
329 if (buf[0] == '\n')
330 lastnl++;
331 else if (buf[buflen-1] == '\n')
332 lastnl = 1;
333 else
334 lastnl = 0;
336 while (!binary && lastnl < 2) {
337 putc('\n', mb.mb_otf);
338 lines++;
339 octets++;
340 lastnl++;
342 Fclose(hp);
343 Fclose(bp);
344 free(buf);
345 fflush(mb.mb_otf);
346 if (ferror(mb.mb_otf)) {
347 perror("decrypted output data");
348 return NULL;
350 x->m_size = x->m_xsize = octets;
351 x->m_lines = x->m_xlines = lines;
352 x->m_block = mailx_blockof(offset);
353 x->m_offset = mailx_offsetof(offset);
354 return x;
357 int
358 ccertsave(void *v)
360 int *ip;
361 int f, *msgvec;
362 char *file = NULL, *str = v;
363 int val = 0;
364 FILE *fp;
366 msgvec = salloc((msgCount + 2) * sizeof *msgvec);
367 if ((file = laststring(str, &f, 1)) == NULL) {
368 fprintf(stderr, "No file to save certificate given.\n");
369 return 1;
371 if (!f) {
372 *msgvec = first(0, MMNORM);
373 if (*msgvec == 0) {
374 if (inhook)
375 return 0;
376 fprintf(stderr,
377 "No messages to get certificates from.\n");
378 return 1;
380 msgvec[1] = 0;
381 } else if (getmsglist(str, msgvec, 0) < 0)
382 return 1;
383 if (*msgvec == 0) {
384 if (inhook)
385 return 0;
386 fprintf(stderr, "No applicable messages.\n");
387 return 1;
389 if ((fp = Fopen(file, "a")) == NULL) {
390 perror(file);
391 return 1;
393 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++)
394 if (smime_certsave(&message[*ip-1], *ip, fp) != OKAY)
395 val = 1;
396 Fclose(fp);
397 if (val == 0)
398 printf("Certificate(s) saved.\n");
399 return val;
402 enum okay
403 rfc2595_hostname_match(const char *host, const char *pattern)
405 if (pattern[0] == '*' && pattern[1] == '.') {
406 pattern++;
407 while (*host && *host != '.')
408 host++;
410 return asccasecmp(host, pattern) == 0 ? OKAY : STOP;
412 #endif /* HAVE_SSL */