getmsglist(): improve [0879986] a bit
[s-mailx.git] / ssl.c
blob7a42a17cff2f04aa7404bc1ceaf60c90391ce0c1
1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ Generic SSL / S/MIME commands.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2016 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
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.
39 #undef n_FILE
40 #define n_FILE ssl
42 #ifndef HAVE_AMALGAMATION
43 # include "nail.h"
44 #endif
46 EMPTY_FILE()
47 #ifdef HAVE_SSL
48 struct ssl_verify_levels {
49 char const sv_name[8];
50 enum ssl_verify_level sv_level;
53 /* Supported SSL/TLS verification methods: update manual on change! */
54 static struct ssl_verify_levels const _ssl_verify_levels[] = {
55 {"strict", SSL_VERIFY_STRICT},
56 {"ask", SSL_VERIFY_ASK},
57 {"warn", SSL_VERIFY_WARN},
58 {"ignore", SSL_VERIFY_IGNORE}
61 FL void
62 ssl_set_verify_level(struct url const *urlp)
64 size_t i;
65 char *cp;
66 NYD_ENTER;
68 ssl_verify_level = SSL_VERIFY_ASK;
69 cp = xok_vlook(ssl_verify, urlp, OXM_ALL);
71 if (cp != NULL) {
72 for (i = 0; i < NELEM(_ssl_verify_levels); ++i)
73 if (!asccasecmp(_ssl_verify_levels[i].sv_name, cp)) {
74 ssl_verify_level = _ssl_verify_levels[i].sv_level;
75 goto jleave;
77 n_err(_("Invalid value of *ssl-verify*: %s\n"), cp);
79 jleave:
80 NYD_LEAVE;
83 FL enum okay
84 ssl_verify_decide(void)
86 enum okay rv = STOP;
87 NYD_ENTER;
89 switch (ssl_verify_level) {
90 case SSL_VERIFY_STRICT:
91 rv = STOP;
92 break;
93 case SSL_VERIFY_ASK:
94 rv = getapproval(NULL, FAL0) ? OKAY : STOP;
95 break;
96 case SSL_VERIFY_WARN:
97 case SSL_VERIFY_IGNORE:
98 rv = OKAY;
99 break;
101 NYD_LEAVE;
102 return rv;
105 FL enum okay
106 smime_split(FILE *ip, FILE **hp, FILE **bp, long xcount, int keep)
108 struct myline {
109 struct myline *ml_next;
110 size_t ml_len;
111 char ml_buf[VFIELD_SIZE(0)];
112 } *head, *tail;
113 char *buf;
114 size_t bufsize, buflen, cnt;
115 int c;
116 enum okay rv = STOP;
117 NYD_ENTER;
119 if ((*hp = Ftmp(NULL, "smimeh", OF_RDWR | OF_UNLINK | OF_REGISTER)) == NULL)
120 goto jetmp;
121 if ((*bp = Ftmp(NULL, "smimeb", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==NULL) {
122 Fclose(*hp);
123 jetmp:
124 n_perr(_("tempfile"), 0);
125 goto jleave;
128 head = tail = NULL;
129 buf = smalloc(bufsize = LINESIZE);
130 cnt = (xcount < 0) ? fsize(ip) : xcount;
132 while (fgetline(&buf, &bufsize, &cnt, &buflen, ip, 0) != NULL &&
133 *buf != '\n') {
134 if (!ascncasecmp(buf, "content-", 8)) {
135 if (keep)
136 fputs("X-Encoded-", *hp);
137 for (;;) {
138 struct myline *ml = smalloc(sizeof *ml -
139 VFIELD_SIZEOF(struct myline, ml_buf) + buflen +1);
140 if (tail != NULL)
141 tail->ml_next = ml;
142 else
143 head = ml;
144 tail = ml;
145 ml->ml_next = NULL;
146 ml->ml_len = buflen;
147 memcpy(ml->ml_buf, buf, buflen +1);
148 if (keep)
149 fwrite(buf, sizeof *buf, buflen, *hp);
150 c = getc(ip);
151 ungetc(c, ip);
152 if (!blankchar(c))
153 break;
154 fgetline(&buf, &bufsize, &cnt, &buflen, ip, 0);
156 continue;
158 fwrite(buf, sizeof *buf, buflen, *hp);
160 fflush_rewind(*hp);
162 while (head != NULL) {
163 fwrite(head->ml_buf, sizeof *head->ml_buf, head->ml_len, *bp);
164 tail = head;
165 head = head->ml_next;
166 free(tail);
168 putc('\n', *bp);
169 while (fgetline(&buf, &bufsize, &cnt, &buflen, ip, 0) != NULL)
170 fwrite(buf, sizeof *buf, buflen, *bp);
171 fflush_rewind(*bp);
173 free(buf);
174 rv = OKAY;
175 jleave:
176 NYD_LEAVE;
177 return rv;
180 FL FILE *
181 smime_sign_assemble(FILE *hp, FILE *bp, FILE *sp, char const *message_digest)
183 char *boundary;
184 int c, lastc = EOF;
185 FILE *op;
186 NYD_ENTER;
188 if ((op = Ftmp(NULL, "smimea", OF_RDWR | OF_UNLINK | OF_REGISTER)) == NULL) {
189 n_perr(_("tempfile"), 0);
190 goto jleave;
193 while ((c = getc(hp)) != EOF) {
194 if (c == '\n' && lastc == '\n')
195 break;
196 putc(c, op);
197 lastc = c;
200 boundary = mime_param_boundary_create();
201 fprintf(op, "Content-Type: multipart/signed;\n"
202 " protocol=\"application/pkcs7-signature\"; micalg=%s;\n"
203 " boundary=\"%s\"\n\n", message_digest, boundary);
204 fprintf(op, "This is a S/MIME signed message.\n\n--%s\n", boundary);
205 while ((c = getc(bp)) != EOF)
206 putc(c, op);
208 fprintf(op, "\n--%s\n", boundary);
209 fputs("Content-Type: application/pkcs7-signature; name=\"smime.p7s\"\n"
210 "Content-Transfer-Encoding: base64\n"
211 "Content-Disposition: attachment; filename=\"smime.p7s\"\n\n", op);
212 while ((c = getc(sp)) != EOF) {
213 if (c == '-') {
214 while ((c = getc(sp)) != EOF && c != '\n');
215 continue;
217 putc(c, op);
220 fprintf(op, "\n--%s--\n", boundary);
222 Fclose(hp);
223 Fclose(bp);
224 Fclose(sp);
226 fflush(op);
227 if (ferror(op)) {
228 n_perr(_("signed output data"), 0);
229 Fclose(op);
230 op = NULL;
231 goto jleave;
233 rewind(op);
234 jleave:
235 NYD_LEAVE;
236 return op;
239 FL FILE *
240 smime_encrypt_assemble(FILE *hp, FILE *yp)
242 FILE *op;
243 int c, lastc = EOF;
244 NYD_ENTER;
246 if ((op = Ftmp(NULL, "smimee", OF_RDWR | OF_UNLINK | OF_REGISTER)) == NULL) {
247 n_perr(_("tempfile"), 0);
248 goto jleave;
251 while ((c = getc(hp)) != EOF) {
252 if (c == '\n' && lastc == '\n')
253 break;
254 putc(c, op);
255 lastc = c;
258 fprintf(op, "Content-Type: application/pkcs7-mime; name=\"smime.p7m\"\n"
259 "Content-Transfer-Encoding: base64\n"
260 "Content-Disposition: attachment; filename=\"smime.p7m\"\n\n");
261 while ((c = getc(yp)) != EOF) {
262 if (c == '-') {
263 while ((c = getc(yp)) != EOF && c != '\n');
264 continue;
266 putc(c, op);
269 Fclose(hp);
270 Fclose(yp);
272 fflush(op);
273 if (ferror(op)) {
274 n_perr(_("encrypted output data"), 0);
275 Fclose(op);
276 op = NULL;
277 goto jleave;
279 rewind(op);
280 jleave:
281 NYD_LEAVE;
282 return op;
285 FL struct message *
286 smime_decrypt_assemble(struct message *m, FILE *hp, FILE *bp)
288 ui32_t lastnl = 0;
289 int binary = 0;
290 char *buf = NULL;
291 size_t bufsize = 0, buflen, cnt;
292 long lines = 0, octets = 0;
293 struct message *x;
294 off_t offset;
295 NYD_ENTER;
297 x = salloc(sizeof *x);
298 *x = *m;
299 fflush(mb.mb_otf);
300 fseek(mb.mb_otf, 0L, SEEK_END);
301 offset = ftell(mb.mb_otf);
303 cnt = fsize(hp);
304 while (fgetline(&buf, &bufsize, &cnt, &buflen, hp, 0) != NULL) {
305 char const *cp;
306 if (buf[0] == '\n')
307 break;
308 if ((cp = thisfield(buf, "content-transfer-encoding")) != NULL)
309 if (!ascncasecmp(cp, "binary", 7))
310 binary = 1;
311 fwrite(buf, sizeof *buf, buflen, mb.mb_otf);
312 octets += buflen;
313 ++lines;
316 { struct time_current save = time_current;
317 time_current_update(&time_current, TRU1);
318 octets += mkdate(mb.mb_otf, "X-Decoding-Date");
319 time_current = save;
321 ++lines;
323 cnt = fsize(bp);
324 while (fgetline(&buf, &bufsize, &cnt, &buflen, bp, 0) != NULL) {
325 lines++;
326 if (!binary && buf[buflen - 1] == '\n' && buf[buflen - 2] == '\r')
327 buf[--buflen - 1] = '\n';
328 fwrite(buf, sizeof *buf, buflen, mb.mb_otf);
329 octets += buflen;
330 if (buf[0] == '\n')
331 ++lastnl;
332 else if (buf[buflen - 1] == '\n')
333 lastnl = 1;
334 else
335 lastnl = 0;
338 while (!binary && lastnl < 2) {
339 putc('\n', mb.mb_otf);
340 ++lines;
341 ++octets;
342 ++lastnl;
345 Fclose(hp);
346 Fclose(bp);
347 free(buf);
349 fflush(mb.mb_otf);
350 if (ferror(mb.mb_otf)) {
351 n_perr(_("decrypted output data"), 0);
352 x = NULL;
353 goto jleave;
355 x->m_size = x->m_xsize = octets;
356 x->m_lines = x->m_xlines = lines;
357 x->m_block = mailx_blockof(offset);
358 x->m_offset = mailx_offsetof(offset);
359 jleave:
360 NYD_LEAVE;
361 return x;
364 FL int
365 c_certsave(void *v)
367 int *ip, *msgvec, val;
368 char *file = NULL, *str = v;
369 FILE *fp;
370 bool_t f;
371 NYD_ENTER;
373 msgvec = salloc((msgCount + 2) * sizeof *msgvec);
374 val = 1;
376 if ((file = laststring(str, &f, TRU1)) == NULL ||
377 (file = file_expand(file)) == NULL) {
378 n_err(_("No file to save certificate given\n"));
379 goto jleave;
382 if (!f) {
383 msgvec[1] = 0;
384 *msgvec = first(0, MMNORM);
385 } else if (getmsglist(str, msgvec, 0) < 0)
386 goto jleave;
387 if (*msgvec == 0) {
388 if (pstate & (PS_HOOK_MASK | PS_ROBOT))
389 val = 0;
390 else
391 n_err(_("No applicable messages\n"));
392 goto jleave;
395 if ((fp = Fopen(file, "a")) == NULL) {
396 n_perr(file, 0);
397 goto jleave;
399 for (val = 0, ip = msgvec;
400 *ip != 0 && UICMP(z, PTR2SIZE(ip - msgvec), <, msgCount); ++ip)
401 if (smime_certsave(&message[*ip - 1], *ip, fp) != OKAY)
402 val = 1;
403 Fclose(fp);
405 if (val == 0)
406 printf("Certificate(s) saved\n");
407 jleave:
408 NYD_LEAVE;
409 return val;
412 FL enum okay
413 rfc2595_hostname_match(char const *host, char const *pattern)
415 enum okay rv;
416 NYD_ENTER;
418 if (pattern[0] == '*' && pattern[1] == '.') {
419 ++pattern;
420 while (*host && *host != '.')
421 ++host;
423 rv = !asccasecmp(host, pattern) ? OKAY : STOP;
424 NYD_LEAVE;
425 return rv;
427 #endif /* HAVE_SSL */
429 /* s-it-mode */