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