1 /*
2  * crypt.c: handles some encryption of messages stuff.
3  *
4  * Written By Michael Sandrof
5  *
6  * Copyright (c) 1990 Michael Sandrof.
7  * Copyright (c) 1991, 1992 Troy Rollo.
8  * Copyright (c) 1992-2014 Matthew R. Green.
9  * All rights reserved.
10  *
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. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include "irc.h"
36 IRCII_RCSID("@(#)$eterna: crypt.c,v 1.84 2021/02/27 23:03:57 mrg Exp $");
37 
38 #include "irccrypt.h"
39 #include "vars.h"
40 #include "ircaux.h"
41 #include "list.h"
42 #include "ctcp.h"
43 #include "output.h"
44 #include "newio.h"
45 
46 #include <sys/wait.h>
47 
48 static	void	add_to_crypt(u_char *, u_char *, CryptFunc, CryptFunc, u_char *);
49 static	int	remove_crypt(u_char *);
50 static	u_char	*do_crypt(u_char *, crypt_key *, int, u_char **);
51 static	void	crypt_get_random_data(u_char *, size_t);
52 
53 #include "cast.c"
54 #if 0
55 #include "aes.c"
56 #endif
57 
58 /*
59  * Crypt: the crypt list structure,  consists of the nickname, and the
60  * encryption key
61  */
62 typedef struct	CryptStru
63 {
64 	struct	CryptStru *next;
65 	u_char	*nick;
66 	crypt_key	*key;
67 }	Crypt;
68 
69 /* crypt_list: the list of nicknames and encryption keys */
70 static	Crypt	*crypt_list = NULL;
71 
72 /*
73  * add_to_crypt: adds the nickname and key pair to the crypt_list.  If the
74  * nickname is already in the list, then the key is changed the the supplied
75  * key.
76  */
77 static	void
add_to_crypt(u_char * nick,u_char * keystr,CryptFunc enc,CryptFunc dec,u_char * type)78 add_to_crypt(u_char *nick, u_char *keystr, CryptFunc enc, CryptFunc dec, u_char *type)
79 {
80 	Crypt	*new;
81 
82 	if ((new = (Crypt *) remove_from_list((List **)(void *)&crypt_list, nick)) != NULL)
83 	{
84 		new_free(&(new->nick));
85 		memset(new->key->key, 0, my_strlen(new->key->key));		/* wipe it out */
86 		new_free(&(new->key->key));
87 		/* XXX destroy cookie first? */
88 		new_free(&(new->key->cookie));
89 		new_free(&(new->key));
90 		new_free(&new);
91 	}
92 	new = new_malloc(sizeof *new);
93 	new->key = new_malloc(sizeof(*new->key));
94 	new->nick = NULL;
95 	new->key->key = NULL;
96 	new->key->type = type;
97 	malloc_strcpy(&(new->nick), nick);
98 	malloc_strcpy(&(new->key->key), keystr);
99 	new->key->crypt = enc;
100 	new->key->decrypt = dec;
101 	new->key->cookie = NULL;
102 	add_to_list((List **)(void *)&crypt_list, (List *) new);
103 }
104 
105 /*
106  * remove_crypt: removes the given nickname from the crypt_list, returning 0
107  * if successful, and 1 if not (because the nickname wasn't in the list)
108  */
109 static	int
remove_crypt(u_char * nick)110 remove_crypt(u_char *nick)
111 {
112 	Crypt	*tmp;
113 
114 	if ((tmp = (Crypt *) list_lookup((List **)(void *)&crypt_list, nick, 0, REMOVE_FROM_LIST)) != NULL)
115 	{
116 		new_free(&tmp->nick);
117 		memset(tmp->key->key, 0, my_strlen(tmp->key->key));		/* wipe it out */
118 		new_free(&tmp->key->key);
119 		new_free(&tmp->key->cookie);
120 		new_free(&tmp->key);
121 		new_free(&tmp);
122 		return (0);
123 	}
124 	return (1);
125 }
126 
127 /*
128  * is_crypted: looks up nick in the crypt_list and returns the encryption key
129  * if found in the list.  If not found in the crypt_list, null is returned.
130  */
131 crypt_key *
is_crypted(u_char * nick)132 is_crypted(u_char *nick)
133 {
134 	Crypt	*tmp;
135 
136 	if (!crypt_list)
137 		return NULL;
138 	if ((tmp = (Crypt *) list_lookup((List **)(void *)&crypt_list, nick, 0, 0)) != NULL)
139 		return (tmp->key);
140 	return NULL;
141 }
142 
143 /*
144  * encrypt_cmd: the ENCRYPT command.  Adds the given nickname and key to the
145  * encrypt list, or removes it, or list the list, you know.
146  */
147 void
encrypt_cmd(u_char * command,u_char * args,u_char * subargs)148 encrypt_cmd(u_char *command, u_char *args, u_char *subargs)
149 {
150 	/* XXX this is getting really, really gross */
151 	CryptFunc enc = DEFAULT_CRYPTER, dec = DEFAULT_DECRYPTER;
152 	u_char	*type = UP(DEFAULT_CRYPTYPE);
153 	u_char	*nick;
154 	int	showkeys = 0;
155 
156 restart:
157 	if ((nick = next_arg(args, &args)) != NULL)
158 	{
159 		size_t len = my_strlen(nick);
160 
161 		if (my_strnicmp(nick, UP("-showkeys"), len) == 0)
162 		{
163 			showkeys = 1;
164 			goto restart;
165 		}
166 		else if (my_strnicmp(nick, UP("-cast"), len) == 0)
167 		{
168 			enc = cast_encrypt_str;
169 			dec = cast_decrypt_str;
170 			type = UP(CAST_STRING);
171 			goto restart;
172 		}
173 #if 0
174 		else if (my_strnicmp(nick, UP("-aes"), len) == 0)
175 		{
176 			enc = aes_encrypt_str;
177 			dec = aes_decrypt_str;
178 			type = UP(AES_STRING);
179 			goto restart;
180 		}
181 #endif
182 
183 		if (args && *args)
184 		{
185 			add_to_crypt(nick, args, enc, dec, type);
186 			say("%s added to the %s crypt", nick, type);
187 		}
188 		else
189 		{
190 			if (remove_crypt(nick))
191 				say("No such nickname in the crypt: %s", nick);
192 			else
193 				say("%s removed from the crypt", nick);
194 		}
195 	}
196 	else
197 	{
198 		if (crypt_list)
199 		{
200 			Crypt	*tmp;
201 
202 			say("The crypt:");
203 			for (tmp = crypt_list; tmp; tmp = tmp->next)
204 				if (showkeys)
205 					put_it("%s with key \"%s\" type %s", tmp->nick, tmp->key->key, tmp->key->type);
206 				else
207 					put_it("%s type %s", tmp->nick, tmp->key->type);
208 		}
209 		else
210 			say("The crypt is empty");
211 	}
212 }
213 
214 static	u_char	*
do_crypt(u_char * str,crypt_key * key,int flag,u_char ** type)215 do_crypt(u_char *str, crypt_key *key, int flag, u_char **type)
216 {
217 	int	in[2],
218 		out[2];
219 	size_t	c;
220 	ssize_t	sc;
221 	u_char	lbuf[CRYPT_BUFFER_SIZE];
222 	u_char	*ptr = NULL,
223 		*crypt_program,
224 		*encrypt_program,
225 		*decrypt_program,
226 		*crypt_str;
227 
228 	encrypt_program = get_string_var(ENCRYPT_PROGRAM_VAR);
229 	decrypt_program = get_string_var(DECRYPT_PROGRAM_VAR);
230 	if ((flag && encrypt_program) || (!flag && decrypt_program))
231 	{
232 #ifdef DAEMON_UID
233 		if (DAEMON_UID == getuid())
234 		{
235 			say("ENCRYPT_PROGRAM not available from daemon mode");
236 			return NULL;
237 		}
238 #endif /* DAEMON_ID */
239 		in[0] = in[1] = -1;
240 		out[0] = out[1] = -1;
241 		if (flag)
242 		{
243 			crypt_str = UP("encryption");
244 			crypt_program = encrypt_program;
245 		}
246 		else
247 		{
248 			crypt_str = UP("decryption");
249 			crypt_program = decrypt_program;
250 		}
251 		if (access(CP(crypt_program), X_OK))
252 		{
253 			say("Unable to execute %s program: %s", crypt_str, crypt_program);
254 			return (NULL);
255 		}
256 		c = my_strlen(str);
257 		if (!flag)
258 			ptr = ctcp_unquote_it(str, &c);
259 		else
260 			malloc_strcpy(&ptr, str);
261 		if (pipe(in) || pipe(out))
262 		{
263 			say("Unable to start %s process: %s", crypt_str, strerror(errno));
264 			if (in[0] != -1)
265 			{
266 				new_close(in[0]);
267 				new_close(in[1]);
268 			}
269 			if (out[0] != -1)
270 			{
271 				new_close(out[0]);
272 				new_close(out[1]);
273 			}
274 		}
275 		switch (fork())
276 		{
277 		case -1:
278 			say("Unable to start %s process: %s", crypt_str, strerror(errno));
279 			return (NULL);
280 		case 0:
281 			MY_SIGNAL(SIGINT, (sigfunc *) SIG_IGN, 0);
282 			dup2(out[1], 1);
283 			dup2(in[0], 0);
284 			new_close(out[0]);
285 			new_close(out[1]);
286 			new_close(in[0]);
287 			new_close(in[1]);
288 			(void)setgid(getgid());
289 			(void)setuid(getuid());
290 			if (get_int_var(OLD_ENCRYPT_PROGRAM_VAR))
291 				execl(CP(crypt_program), CP(crypt_program), key->key, NULL);
292 			else
293 				execl(CP(crypt_program), CP(crypt_program), NULL);
294 			exit(0);
295 		default:
296 			new_close(out[1]);
297 			new_close(in[0]);
298 			if (get_int_var(OLD_ENCRYPT_PROGRAM_VAR) == 0)
299 			{
300 				(void)write(in[1], key->key, my_strlen(key->key));
301 				(void)write(in[1], "\n", 1);
302 			}
303 			(void)write(in[1], ptr, c);
304 			new_close(in[1]);
305 			sc = read(out[0], lbuf, sizeof lbuf);
306 			wait(NULL);
307 			if (sc > 0)
308 				lbuf[sc] = '\0';
309 			new_close(out[0]);
310 			break;
311 		}
312 		new_free(&ptr);
313 		if (flag)
314 			ptr = ctcp_quote_it(lbuf, my_strlen(lbuf));
315 		else
316 			malloc_strcpy(&ptr, lbuf);
317 	}
318 	else
319 	{
320 		c = my_strlen(str);
321 		if (flag)
322 		{
323 			if (key->crypt(key, &str, &c) != 0)
324 			{
325 				yell("--- do_crypt(): crypto encrypt failed");
326 				return 0;
327 			}
328 			ptr = ctcp_quote_it(str, c);
329 		}
330 		else
331 		{
332 			ptr = ctcp_unquote_it(str, &c);
333 			if (key->decrypt(key, &ptr, &c) != 0)
334 			{
335 				yell("--- do_crypt(): crypto decrypt failed");
336 				return 0;
337 			}
338 		}
339 	}
340 	if (type)
341 		*type = key->type;
342 	return (ptr);
343 }
344 
345 /*
346  * crypt_msg: Executes the encryption program on the given string with the
347  * given key.  If flag is true, the string is encrypted and the returned
348  * string is ready to be sent over irc.  If flag is false, the string is
349  * decrypted and the returned string should be readable.
350  */
351 u_char	*
crypt_msg(u_char * str,crypt_key * key,int flag)352 crypt_msg(u_char *str, crypt_key *key, int flag)
353 {
354 	static	u_char	lbuf[CRYPT_BUFFER_SIZE];
355 	u_char	*ptr,
356 		*rest,
357 		*type;
358 	int	on = 1;
359 
360 	if (flag)
361 	{
362 		*lbuf = '\0';
363 		while ((rest = my_index(str, '\005')) != NULL)
364 		{
365 			*(rest++) = '\0';
366 			if (on && *str && (ptr = do_crypt(str, key, flag, &type)))
367 			{
368 				snprintf(CP(lbuf), sizeof lbuf, "%c%.30s ", CTCP_DELIM_CHAR, type);
369 				my_strmcat(lbuf, ptr, sizeof lbuf);
370 				my_strmcat(lbuf, CTCP_DELIM_STR, sizeof lbuf);
371 				new_free(&ptr);
372 			}
373 			else
374 				my_strmcat(lbuf, str, sizeof lbuf);
375 			on = !on;
376 			str = rest;
377 		}
378 		if (on && (ptr = do_crypt(str, key, flag, &type)))
379 		{
380 			snprintf(CP(lbuf), sizeof lbuf, "%c%.30s ", CTCP_DELIM_CHAR, type);
381 			my_strmcat(lbuf, ptr, sizeof lbuf);
382 			my_strmcat(lbuf, CTCP_DELIM_STR, sizeof lbuf);
383 			new_free(&ptr);
384 		}
385 		else
386 			my_strmcat(lbuf, str, sizeof lbuf);
387 	}
388 	else
389 	{
390 		if ((ptr = do_crypt(str, key, flag, &type)) != NULL)
391 		{
392 			my_strmcpy(lbuf, ptr, sizeof lbuf);
393 			new_free(&ptr);
394 		}
395 		else
396 			my_strmcat(lbuf, str, sizeof lbuf);
397 	}
398 	return (lbuf);
399 }
400 
401 #ifdef HAVE_DEV_RANDOM
402 static void alarmer(int);
403 
404 static void
alarmer(int dummy)405 alarmer(int dummy)
406 {
407 }
408 #endif
409 
410 static void
crypt_get_random_data(u_char * buf,size_t buflen)411 crypt_get_random_data(u_char *buf, size_t buflen)
412 {
413 	size_t	i;
414 #ifdef HAVE_DEV_RANDOM
415 	static	int	devrndfd = -1;
416 	size_t	remain = buflen;
417 
418 	if (devrndfd == -1)
419 	{
420 		devrndfd = open(DEV_RANDOM_PATH, O_RDONLY);
421 
422 		if (devrndfd == -1)
423 		{
424 			static int first = 1;
425 
426 			if (first)
427 			{
428 				first = 0;
429 				yell("--- HELP!!!! crypt_dev_random_byte: can not open %s: %s",
430 				    DEV_RANDOM_PATH, strerror(errno));
431 				goto do_random_instead_no_alarm;
432 			}
433 		}
434 	}
435 	if (devrndfd == -2)
436 		goto do_random_instead_no_alarm;
437 
438 	(void)MY_SIGNAL(SIGALRM, (sigfunc *) alarmer, 0);
439 	for (; remain > 0;) {
440 		alarm(2);
441 		ssize_t rv = read(devrndfd, buf, remain);
442 		alarm(0);
443 		if (rv > 0) {
444 			remain -= rv;
445 			continue;
446 		}
447 		(void)MY_SIGNAL(SIGALRM, (sigfunc *) SIG_DFL, 0);
448 		/* if we were just interrupted, don't bail on /dev/random */
449 		if (errno == EINTR)
450 			yell("--- crypt_dev_random_byte: interrupt -- "
451 			     "using random()");
452 		else
453 			yell("--- HELP!  crypt_dev_random_byte(): read of %zu "
454 			     "bytes on %s failed: %s",
455 			     buflen, DEV_RANDOM_PATH, strerror(errno));
456 		yell("--- using random()");
457 		break;
458 	}
459 
460 	alarm(0);
461 	(void)MY_SIGNAL(SIGALRM, (sigfunc *) SIG_DFL, 0);
462 do_random_instead_no_alarm:
463 #endif
464 	for (i = 0; i < buflen; i++)
465 	{
466 		buf[i] = (random() & 255);
467 	}
468 }
469