1 /*
2  * These are helping routines for the main module of CNTLM
3  *
4  * CNTLM is free software; you can redistribute it and/or modify it under the
5  * terms of the GNU General Public License as published by the Free Software
6  * Foundation; either version 2 of the License, or (at your option) any later
7  * version.
8  *
9  * CNTLM is distributed in the hope that it will be useful, but WITHOUT ANY
10  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
12  * details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
16  * St, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Copyright (c) 2007 David Kubicek
19  *
20  */
21 
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <string.h>
25 #include <strings.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <stdio.h>
29 #include <errno.h>
30 #include <ctype.h>
31 #include <syslog.h>
32 
33 #include "config/config.h"
34 #include "swap.h"
35 #include "utils.h"
36 #include "socket.h"
37 
38 char hextab[17] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 0};
39 int hexindex[128] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
40 	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
41 	-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,
42 	-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
43 	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,
44 	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
45 
myexit(int rc)46 void myexit(int rc) {
47 	if (rc)
48 		fprintf(stderr, "Exitting with error. Check daemon logs or run with -v.\n");
49 
50 	exit(rc);
51 }
52 
croak(const char * msg,int console)53 void croak(const char *msg, int console) {
54 	if (console)
55 		printf("%s", msg);
56 	else
57 		syslog(LOG_ERR, "%s", msg);
58 
59 	myexit(1);
60 }
61 
62 /*
63  * Add a new item to a list. Every plist_t variable must be
64  * initialized to NULL (or pass NULL for "list" when adding
65  * the first item). This is for simplicity's sake (we don't
66  * need any plist_new).
67  *
68  * This list type allows to store an arbitrary pointer
69  * associating it with the key.
70  */
plist_add(plist_t list,unsigned long key,void * aux)71 plist_t plist_add(plist_t list, unsigned long key, void *aux) {
72 	plist_t tmp, t = list;
73 
74 	tmp = malloc(sizeof(struct plist_s));
75 	tmp->key = key;
76 	tmp->aux = aux;
77 	tmp->next = NULL;
78 
79 	if (list == NULL)
80 		return tmp;
81 
82 	while (t->next)
83 		t = t->next;
84 
85 	t->next = tmp;
86 
87 	return list;
88 }
89 
90 /*
91  * Delete an item from the list, possibly returning NULL when
92  * the list is empty or nothing was found.
93  */
plist_del(plist_t list,unsigned long key)94 plist_t plist_del(plist_t list, unsigned long key) {
95 	plist_t ot = NULL, t = list;
96 
97 	while (t) {
98 		if (t->key == key)
99 			break;
100 		ot = t;
101 		t = t->next;
102 	}
103 
104 	if (t) {
105 		plist_t tmp = t->next;
106 
107 		if (t->aux)
108 			free(t->aux);
109 		free(t);
110 		if (ot == NULL)
111 			return tmp;
112 
113 		ot->next = tmp;
114 	}
115 
116 	return list;
117 }
118 
119 /*
120  * Return true if an item is present in the list.
121  */
plist_in(plist_t list,unsigned long key)122 int plist_in(plist_t list, unsigned long key) {
123 	plist_t t = list;
124 
125 	while (t) {
126 		if (t->key == key)
127 			break;
128 		t = t->next;
129 	}
130 
131 	return (t != NULL);
132 }
133 
134 /*
135  * For debugging purposes - dump the entire contents
136  * of a list.
137  */
plist_dump(plist_t list)138 void plist_dump(plist_t list) {
139 	plist_t t;
140 
141 	t = list;
142 	while (t) {
143 		printf("List data: %lu => 0x%8p\n", (unsigned long int)t->key, t->aux);
144 		t = t->next;
145 	}
146 }
147 
148 /*
149  * Return the pointer associated with the key.
150  */
plist_get(plist_t list,int key)151 char *plist_get(plist_t list, int key) {
152 	plist_t t = list;
153 
154 	while (t) {
155 		if (t->key == key)
156 			break;
157 		t = t->next;
158 	}
159 
160 	return (t == NULL ? NULL : t->aux);
161 }
162 
163 /*
164  * Scan the list for an open descriptor (socket), possibly
165  * discarding all closed ones on the way. Return the first
166  * match.
167  *
168  * Use this method only for lists of descriptors!
169  *
170  * In conjunction with plist_add, the list behaves as a FIFO.
171  * This feature is used for rotating cached connections in the
172  * list, so that none is left too long unused (proxy timeout).
173  *
174  * Returns key value (descriptor) and if aux != NULL, *aux gets
175  * aux pointer value (which caller must free if != NULL).
176  */
177 
plist_pop(plist_t * list,void ** aux)178 int plist_pop(plist_t *list, void **aux) {
179 	plist_t tmp, t;
180 	int id = 0;
181 	int ok = 0;
182 	void *a = NULL;
183 
184 	if (list == NULL || *list == NULL)
185 		return 0;
186 
187 	t = *list;
188 	while (!ok && t) {
189 		id = t->key;
190 		a = t->aux;
191 		tmp = t->next;
192 
193 		if (so_closed(id)) {
194 			close(id);
195 			if (t->aux)
196 				free(t->aux);
197 		} else
198 			ok = 1;
199 
200 		free(t);
201 		t = tmp;
202 	}
203 
204 	*list = t;
205 
206 	if (ok) {
207 		if (aux != NULL)
208 			*aux = a;
209 		return id;
210 	}
211 
212 	return 0;
213 }
214 
215 /*
216  * Return the number of items in a list.
217  */
plist_count(plist_t list)218 int plist_count(plist_t list) {
219 	plist_t t = list;
220 	int rc = 0;
221 
222 	while (t) {
223 		rc++;
224 		t = t->next;
225 	}
226 
227 	return rc;
228 }
229 
230 /*
231  * Free the list.
232  */
plist_free(plist_t list)233 plist_t plist_free(plist_t list) {
234 	plist_t t = list;
235 
236 	while (list) {
237 		t = list->next;
238 		if (list->aux)
239 			free(list->aux);
240 		free(list);
241 		list = t;
242 	}
243 
244 	return NULL;
245 }
246 
247 /*
248  * The same as plist_add. Here we have two other arguments.
249  * They are boolean flags - HLIST_ALLOC means to duplicate a
250  * key/value, HLIST_NOALLOC means to store the pointer directly.
251  *
252  * Caller decides this on a by-call basis. Part of the manipulation
253  * routines is a "free". That method always deallocates both the
254  * key and the value. So for static or temporary keys/values,
255  * the caller can instruct us to duplicate the necessary amount
256  * of heap. This mechanism is used to minimize memory-related
257  * bugs throughout the code and tons of free's.
258  */
hlist_add(hlist_t list,char * key,char * value,hlist_add_t allockey,hlist_add_t allocvalue)259 hlist_t hlist_add(hlist_t list, char *key, char *value, hlist_add_t allockey, hlist_add_t allocvalue) {
260 	hlist_t tmp, t = list;
261 
262 	if (key == NULL || value == NULL)
263 		return list;
264 
265 	tmp = malloc(sizeof(struct hlist_s));
266 	tmp->key = (allockey == HLIST_ALLOC ? strdup(key) : key);
267 	tmp->value = (allocvalue == HLIST_ALLOC ? strdup(value) : value);
268 	tmp->next = NULL;
269 	tmp->islist = 0;
270 
271 	if (list == NULL)
272 		return tmp;
273 
274 	while (t->next)
275 		t = t->next;
276 
277 	t->next = tmp;
278 
279 	return list;
280 }
281 
282 /*
283  * Return a duplicate of the list (copy).
284  */
hlist_dup(hlist_t list)285 hlist_t hlist_dup(hlist_t list) {
286 	hlist_t tmp = NULL, t = list;
287 
288 	while (t) {
289 		tmp = hlist_add(tmp, t->key, t->value, HLIST_ALLOC, HLIST_ALLOC);
290 		t = t->next;
291 	}
292 
293 	return tmp;
294 }
295 
296 /*
297  * Remove an item from the list.
298  */
hlist_del(hlist_t list,const char * key)299 hlist_t hlist_del(hlist_t list, const char *key) {
300 	hlist_t ot = NULL, t = list;
301 
302 	while (t) {
303 		if (!strcasecmp(t->key, key))
304 			break;
305 		ot = t;
306 		t = t->next;
307 	}
308 
309 	if (t) {
310 		hlist_t tmp = t->next;
311 
312 		free(t->key);
313 		free(t->value);
314 		free(t);
315 
316 		if (ot == NULL)
317 			return tmp;
318 
319 		ot->next = tmp;
320 	}
321 
322 	return list;
323 }
324 
325 /*
326  * Change the value of a key. If add is true, we store it in the
327  * list if the key is not found. Unlike hlist_add, which offers
328  * pointer storage or memory duplication for both the key and the
329  * value separately, hlist_mod always duplicates.
330  *
331  * Used to add a header, which might already be present.
332  */
hlist_mod(hlist_t list,char * key,char * value,int add)333 hlist_t hlist_mod(hlist_t list, char *key, char *value, int add) {
334 	hlist_t t = list;
335 
336 	while (t) {
337 		if (!strcasecmp(t->key, key))
338 			break;
339 		t = t->next;
340 	}
341 
342 	if (t) {
343 		free(t->value);
344 		t->value = strdup(value);
345 	} else if (add) {
346 		list = hlist_add(list, key, value, HLIST_ALLOC, HLIST_ALLOC);
347 	}
348 
349 	return list;
350 }
351 
352 /*
353  * Return true is the key is in the list.
354  */
hlist_in(hlist_t list,const char * key)355 int hlist_in(hlist_t list, const char *key) {
356 	hlist_t t = list;
357 
358 	while (t) {
359 		if (!strcasecmp(t->key, key))
360 			break;
361 		t = t->next;
362 	}
363 
364 	return (t != NULL);
365 }
366 
367 /*
368  * Return the number of items in a list.
369  */
hlist_count(hlist_t list)370 int hlist_count(hlist_t list) {
371 	hlist_t t = list;
372 	int rc = 0;
373 
374 	while (t) {
375 		rc++;
376 		t = t->next;
377 	}
378 
379 	return rc;
380 }
381 
382 /*
383  * Return the value for the key.
384  */
hlist_get(hlist_t list,const char * key)385 char *hlist_get(hlist_t list, const char *key) {
386 	hlist_t t = list;
387 
388 	while (t) {
389 		if (!strcasecmp(t->key, key))
390 			break;
391 		t = t->next;
392 	}
393 
394 	return (t == NULL ? NULL : t->value);
395 }
396 
397 /*
398  * Test if substr is part of the header's value.
399  * Both case-insensitive.
400  */
hlist_subcmp(hlist_t list,const char * key,const char * substr)401 int hlist_subcmp(hlist_t list, const char *key, const char *substr) {
402 	int found = 0;
403 	char *tmp, *low;
404 
405 	lowercase(low = strdup(substr));
406 	tmp = hlist_get(list, key);
407 	if (tmp) {
408 		lowercase(tmp = strdup(tmp));
409 		if (strstr(tmp, low))
410 			found = 1;
411 
412 		free(tmp);
413 	}
414 
415 	free(low);
416 	return found;
417 }
418 
419 /*
420  * Test if substr is part of the header's value.
421  * Both case-insensitive, checks all headers, not just first one.
422  */
hlist_subcmp_all(hlist_t list,const char * key,const char * substr)423 int hlist_subcmp_all(hlist_t list, const char *key, const char *substr) {
424 	hlist_t t = list;
425 	int found = 0;
426 	char *tmp, *low;
427 
428 	lowercase(low = strdup(substr));
429 	while (t) {
430 		if (!strcasecmp(t->key, key)) {
431 			lowercase(tmp = strdup(t->value));
432 			if (strstr(tmp, low))
433 				found = 1;
434 
435 			free(tmp);
436 		}
437 		t = t->next;
438 	}
439 
440 	free(low);
441 	return found;
442 }
443 
444 /*
445  * Free the list. For more about list memory management,
446  * se hlist_add.
447  */
hlist_free(hlist_t list)448 hlist_t hlist_free(hlist_t list) {
449 	hlist_t t = list;
450 
451 	while (list) {
452 		t = list->next;
453 
454 		free(list->key);
455 		free(list->value);
456 		free(list);
457 
458 		list = t;
459 	}
460 
461 	return NULL;
462 }
463 
464 /*
465  * This is for debugging purposes.
466  */
hlist_dump(hlist_t list)467 void hlist_dump(hlist_t list) {
468 	hlist_t t;
469 
470 	t = list;
471 	while (t) {
472 		printf("%-30s => %s\n", t->key, t->value);
473 		t = t->next;
474 	}
475 }
476 
477 /*
478  * Standard substr. To prevent modification of the source
479  * (terminating \x0), return the result in a new memory.
480  */
substr(const char * src,int pos,int len)481 char *substr(const char *src, int pos, int len) {
482 	int l;
483 	char *tmp;
484 
485 	if (len == 0)
486 		len = strlen(src);
487 
488 	l = MIN(len, strlen(src)-pos);
489 	if (l <= 0)
490 		return new(1);
491 
492 	tmp = new(l+1);
493 	strlcpy(tmp, src+pos, l+1);
494 
495 	return tmp;
496 }
497 
498 /*
499  * Allocate memory and initialize a new rr_data_t structure.
500  */
new_rr_data(void)501 rr_data_t new_rr_data(void) {
502 	rr_data_t data;
503 
504 	data = malloc(sizeof(struct rr_data_s));
505 	data->req = 0;
506 	data->code = 0;
507 	data->skip_http = 0;
508 	data->body_len = 0;
509 	data->empty = 1;
510 	data->port = 0;
511 	data->headers = NULL;
512 	data->method = NULL;
513 	data->url = NULL;
514 	data->rel_url = NULL;
515 	data->hostname = NULL;
516 	data->http = NULL;
517 	data->msg = NULL;
518 	data->body = NULL;
519 	data->errmsg = NULL; 			/* for static strings - we don't free, dup, nor copy */
520 
521 	return data;
522 }
523 
524 /*
525  * Copy the req/res data.
526  */
copy_rr_data(rr_data_t dst,rr_data_t src)527 rr_data_t copy_rr_data(rr_data_t dst, rr_data_t src) {
528 	if (src == NULL || dst == NULL)
529 		return NULL;
530 
531 	reset_rr_data(dst);
532 	dst->req = src->req;
533 	dst->code = src->code;
534 	dst->skip_http = src->skip_http;
535 	dst->body_len = src->body_len;
536 	dst->empty = src->empty;
537 	dst->port = src->port;
538 
539 	if (src->headers)
540 		dst->headers = hlist_dup(src->headers);
541 	if (src->method)
542 		dst->method = strdup(src->method);
543 	if (src->url)
544 		dst->url = strdup(src->url);
545 	if (src->rel_url)
546 		dst->rel_url = strdup(src->rel_url);
547 	if (src->hostname)
548 		dst->hostname = strdup(src->hostname);
549 	if (src->http)
550 		dst->http = strdup(src->http);
551 	if (src->msg)
552 		dst->msg = strdup(src->msg);
553 	if (src->body && src->body_len > 0) {
554 		dst->body = new(src->body_len);
555 		memcpy(dst->body, src->body, src->body_len);
556 	}
557 
558 	return dst;
559 }
560 
561 /*
562  * Duplicate the req/res data.
563  */
dup_rr_data(rr_data_t data)564 rr_data_t dup_rr_data(rr_data_t data) {
565 	rr_data_t tmp;
566 
567 	if (data == NULL)
568 		return NULL;
569 
570 	tmp = new_rr_data();
571 	return copy_rr_data(tmp, data);
572 }
573 
574 /*
575  * Reset, freeing if neccessary
576  */
reset_rr_data(rr_data_t data)577 rr_data_t reset_rr_data(rr_data_t data) {
578 	if (data == NULL)
579 		return NULL;
580 
581 	data->req = 0;
582 	data->code = 0;
583 	data->skip_http = 0;
584 	data->body_len = 0;
585 	data->empty = 1;
586 	data->port = 0;
587 
588 	if (data->headers) hlist_free(data->headers);
589 	if (data->method) free(data->method);
590 	if (data->url) free(data->url);
591 	if (data->rel_url) free(data->rel_url);
592 	if (data->hostname) free(data->hostname);
593 	if (data->http) free(data->http);
594 	if (data->msg) free(data->msg);
595 	if (data->body) free(data->body);
596 
597 	data->headers = NULL;
598 	data->method = NULL;
599 	data->url = NULL;
600 	data->rel_url = NULL;
601 	data->hostname = NULL;
602 	data->http = NULL;
603 	data->msg = NULL;
604 	data->body = NULL;
605 	data->errmsg = NULL;
606 
607 	return data;
608 }
609 
610 /*
611  * Free rr_data_t structure. We also take care of freeing
612  * the memory of its members.
613  */
free_rr_data(rr_data_t data)614 void free_rr_data(rr_data_t data) {
615 	if (data == NULL)
616 		return;
617 
618 	if (data->headers) hlist_free(data->headers);
619 	if (data->method) free(data->method);
620 	if (data->url) free(data->url);
621 	if (data->rel_url) free(data->rel_url);
622 	if (data->hostname) free(data->hostname);
623 	if (data->http) free(data->http);
624 	if (data->msg) free(data->msg);
625 	if (data->body) free(data->body);
626 	free(data);
627 }
628 
629 /*
630  * Cut the whitespace at the end of a string.
631  */
trimr(char * buf)632 char *trimr(char *buf) {
633 	int i;
634 
635 	for (i = strlen(buf)-1; i >= 0 && isspace(buf[i]); --i);
636 	buf[i+1] = 0;
637 
638 	return buf;
639 }
640 
641 #if config_strdup == 0
642 /*
643  * Our implementation of non-POSIX strdup()
644  */
strdup(const char * src)645 char *strdup(const char *src) {
646 	size_t len;
647 	char *tmp;
648 
649 	if (!src)
650 		return NULL;
651 
652 	len = strlen(src)+1;
653 	tmp = calloc(1, len);
654 	memcpy(tmp, src, len-1);
655 
656 	return tmp;
657 }
658 #endif
659 
660 /*
661  * More intuitive version of strncpy with string termination
662  * from OpenBSD
663  */
strlcpy(char * dst,const char * src,size_t siz)664 size_t strlcpy(char *dst, const char *src, size_t siz) {
665         char *d = dst;
666         const char *s = src;
667         size_t n = siz;
668 
669         /* Copy as many bytes as will fit */
670         if (n != 0) {
671                 while (--n != 0) {
672                         if ((*d++ = *s++) == '\0')
673                                 break;
674                 }
675         }
676 
677         /* Not enough room in dst, add NUL and traverse rest of src */
678         if (n == 0) {
679                 if (siz != 0)
680                         *d = '\0';                /* NUL-terminate dst */
681                 while (*s++);
682         }
683 
684         return (s - src - 1);        /* count does not include NUL */
685 }
686 
687 /*
688  * More intuitive version os strncat with string termination
689  * from OpenBSD
690  */
strlcat(char * dst,const char * src,size_t siz)691 size_t strlcat(char *dst, const char *src, size_t siz) {
692         char *d = dst;
693         const char *s = src;
694         size_t n = siz;
695         size_t dlen;
696 
697         /* Find the end of dst and adjust bytes left but don't go past end */
698         while (n-- != 0 && *d != '\0')
699                 d++;
700 
701         dlen = d - dst;
702         n = siz - dlen;
703 
704         if (n == 0)
705                 return(dlen + strlen(s));
706 
707         while (*s != '\0') {
708                 if (n != 1) {
709                         *d++ = *s;
710                         n--;
711                 }
712                 s++;
713         }
714         *d = '\0';
715 
716         return (dlen + (s - src));        /* count does not include NUL */
717 }
718 
719 /*
720  * Shortcut for malloc/memset zero.
721  */
new(size_t size)722 char *new(size_t size) {
723 	char *tmp;
724 
725 	tmp = malloc(size);
726 	memset(tmp, 0, size);
727 
728 	return tmp;
729 }
730 
731 /*
732  * Self-explanatory.
733  */
lowercase(char * str)734 char *lowercase(char *str) {
735 	int i;
736 
737 	for (i = 0; i < strlen(str); ++i)
738 		str[i] = tolower(str[i]);
739 
740 	return str;
741 }
742 
743 /*
744  * Self-explanatory.
745  */
uppercase(char * str)746 char *uppercase(char *str) {
747 	int i;
748 
749 	for (i = 0; i < strlen(str); ++i)
750 		str[i] = toupper(str[i]);
751 
752 	return str;
753 }
754 
unicode(char ** dst,char * src)755 int unicode(char **dst, char *src) {
756 	char *tmp;
757 	int l, i;
758 
759 	if (!src) {
760 		*dst = NULL;
761 		return 0;
762 	}
763 
764 	l = MIN(64, strlen(src));
765 	tmp = new(2*l);
766 	for (i = 0; i < l; ++i)
767 		tmp[2*i] = src[i];
768 
769 	*dst = tmp;
770 	return 2*l;
771 }
772 
urlencode(const char * str)773 char *urlencode(const char *str) {
774 	char *tmp;
775 	int i, pos;
776 
777 	tmp = new(strlen(str)*3 + 1);
778 	for (pos = 0, i = 0; i < strlen(str); ++i) {
779 		if (isdigit(str[i]) || (tolower(str[i]) >= 'a' && tolower(str[i]) <= 'z') || str[i] == '.' || str[i] == '-' || str[i] == '_' || str[i] == '~') {
780 			tmp[pos++] = str[i];
781 		} else {
782 			sprintf(tmp+pos, "%%%X", (unsigned char)str[i]);
783 			pos += 3;
784 		}
785 	}
786 
787 	return tmp;
788 }
789 
printmem(char * src,size_t len,int bitwidth)790 char *printmem(char *src, size_t len, int bitwidth) {
791 	char *tmp;
792 	int i;
793 
794 	tmp = new(2*len+1);
795 	for (i = 0; i < len; ++i) {
796 		tmp[i*2] = hextab[((uint8_t)src[i] ^ (uint8_t)(7-bitwidth)) >> 4];
797 		tmp[i*2+1] = hextab[(src[i] ^ (uint8_t)(7-bitwidth)) & 0x0F];
798 	}
799 
800 	return tmp;
801 }
802 
scanmem(char * src,int bitwidth)803 char *scanmem(char *src, int bitwidth) {
804 	int h, l, i, bytes;
805 	char *tmp;
806 
807 	if (strlen(src) % 2)
808 		return NULL;
809 
810 	bytes = strlen(src)/2;
811 	tmp = new(bytes+1);
812 	for (i = 0; i < bytes; ++i) {
813 		h = hexindex[(int)src[i*2]];
814 		l = hexindex[(int)src[i*2+1]];
815 		if (h < 0 || l < 0) {
816 			free(tmp);
817 			return NULL;
818 		}
819 		tmp[i] = ((h << 4) + l) ^ (uint8_t)(7-bitwidth);
820 	}
821 	tmp[i] = 0;
822 
823 	return tmp;
824 }
825 
826 
827 
828 /*
829  * BASE64 CODE FROM MUTT BEGIN - ORIGINAL COPYRIGHT APPLIES:
830  *
831  * Copyright (C) 1996-2001 Michael R. Elkins <me@cs.hmc.edu>
832  * Copyright (C) 1996-2001 Brandon Long <blong@fiction.net>
833  * Copyright (C) 1997-2001 Thomas Roessler <roessler@guug.de>
834  * Copyright (C) 1998-2001 Werner Koch <wk@isil.d.shuttle.de>
835  * Copyright (C) 1999-2001 Brendan Cully <brendan@kublai.com>
836  * Copyright (C) 1999-2001 Tommi Komulainen <Tommi.Komulainen@iki.fi>
837  * Copyright (C) 2000-2001 Edmund Grimley Evans <edmundo@rano.org>
838  *
839  */
840 
841 #define BAD     	-1
842 #define base64val(c)	index64[(unsigned int)(c)]
843 
844 char base64[64] = {
845 	'A','B','C','D','E','F','G','H','I','J','K','L','M','N',
846 	'O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b',
847 	'c','d','e','f','g','h','i','j','k','l','m','n','o','p',
848 	'q','r','s','t','u','v','w','x','y','z','0','1','2','3',
849 	'4','5','6','7','8','9','+','/'
850 };
851 
852 int index64[128] = {
853 	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
854 	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
855 	-1,-1,-1,-1,-1,62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,
856 	61,-1,-1,-1,-1,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,
857 	14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,
858 	27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,
859 	46,47,48,49,50,51,-1,-1,-1,-1,-1
860 };
861 
to_base64(unsigned char * out,const unsigned char * in,size_t len,size_t olen)862 void to_base64(unsigned char *out, const unsigned char *in, size_t len, size_t olen) {
863 	while (len >= 3 && olen > 10) {
864 		*out++ = base64[in[0] >> 2];
865 		*out++ = base64[((in[0] << 4) & 0x30) | (in[1] >> 4)];
866 		*out++ = base64[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
867 		*out++ = base64[in[2] & 0x3f];
868 		olen  -= 4;
869 		len   -= 3;
870 		in    += 3;
871 	}
872 
873 	/* clean up remainder */
874 	if (len > 0 && olen > 4) {
875 		unsigned char fragment;
876 
877 		*out++ = base64[in[0] >> 2];
878 		fragment = (in[0] << 4) & 0x30;
879 		if (len > 1)
880 		fragment |= in[1] >> 4;
881 		*out++ = base64[fragment];
882 		*out++ = (len < 2) ? '=' : base64[(in[1] << 2) & 0x3c];
883 		*out++ = '=';
884 	}
885 	*out = '\0';
886 }
887 
888 /* Convert '\0'-terminated base 64 string to raw bytes.
889  * Returns length of returned buffer, or -1 on error */
from_base64(char * out,const char * in)890 int from_base64(char *out, const char *in)
891 {
892 	int len = 0;
893 	register unsigned char digit1, digit2, digit3, digit4;
894 
895 	do {
896 		digit1 = in[0];
897 		if (digit1 > 127 || base64val (digit1) == BAD)
898 			return -1;
899 
900 		digit2 = in[1];
901 		if (digit2 > 127 || base64val (digit2) == BAD)
902 			return -1;
903 
904 		digit3 = in[2];
905 		if (digit3 > 127 || ((digit3 != '=') && (base64val (digit3) == BAD)))
906 			return -1;
907 
908 		digit4 = in[3];
909 		if (digit4 > 127 || ((digit4 != '=') && (base64val (digit4) == BAD)))
910 			return -1;
911 
912 		in += 4;
913 
914 		/* digits are already sanity-checked */
915 		*out++ = (base64val(digit1) << 2) | (base64val(digit2) >> 4);
916 		len++;
917 		if (digit3 != '=') {
918 			*out++ = ((base64val(digit2) << 4) & 0xf0) | (base64val(digit3) >> 2);
919 			len++;
920 			if (digit4 != '=') {
921 				*out++ = ((base64val(digit3) << 6) & 0xc0) | base64val(digit4);
922 				len++;
923 			}
924 		}
925 	} while (*in && digit4 != '=');
926 
927 	return len;
928 }
929 /*
930  * CODE FROM MUTT END
931  */
932