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