1 /*	$Id: libarms.c 20956 2012-01-31 04:04:25Z m-oki $	*/
2 
3 /*
4  * Copyright (c) 2012, Internet Initiative Japan, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
21  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include "config.h"
31 
32 #include <stdlib.h>
33 #include <inttypes.h>
34 #include <sys/types.h>
35 #include <sys/time.h>
36 #include <string.h>
37 
38 #include <sys/socket.h>/*test*/
39 #include <unistd.h>
40 #include <netdb.h>
41 
42 #include <openssl/err.h>
43 
44 #include <libarms_resource.h>
45 #include <libarms_log.h>
46 #include <lsconfig.h>
47 #include <armsd_conf.h>
48 #include <axp_extern.h>
49 #include <module_db_mi.h>
50 
51 #include <libarms/malloc.h>
52 #include <libarms/ssl.h>
53 #include <libarms/queue.h>
54 #include <transaction/transaction.h>
55 #include <transaction/ssltunnel.h>
56 #include <protocol/arms_methods.h>
57 
58 #include "compat.h"
59 
60 #if 0
61 static void
62 print_openssl_ciphers(void)
63 {
64 	SSL_CTX*	ctx;
65 
66 	printf("OPENSSL_VERSION_TEXT: %s\n", OPENSSL_VERSION_TEXT);
67 
68 	ctx = SSL_CTX_new(TLSv1_server_method());
69 	if (ctx) {
70 		SSL*	ssl;
71 
72 		ssl = SSL_new(ctx);
73 		if (ssl) {
74 			int	i;
75 			const char *ciphers;
76 			STACK_OF(SSL_CIPHER) *sk;
77 
78 			printf("SSL_version: %x\n", SSL_version(ssl));
79 			for (i = 0; (ciphers = SSL_get_cipher_list(ssl, i)) != NULL; i ++) {
80 				printf("SSL_get_cipher_list[%d]: %s\n", i, ciphers);
81 			}
82 			printf("SSL_get_ciphers:\n");
83 			sk = SSL_get_ciphers(ssl);
84 			for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) {
85 				char buf[512];
86 
87 				printf("%s\n", SSL_CIPHER_description(sk_SSL_CIPHER_value(sk, i), buf, sizeof(buf)));
88 				}
89 SSL_free(ssl);
90 		} else {
91 			printf("SSL_version: Error: unknown\n");
92 		}
93 		SSL_CTX_free(ctx);
94 	} else {
95 		fprintf(stderr, "Error: SSL_CTX_new()\n");
96 	}
97 }
98 #endif
99 
100 void
arms_sleep(unsigned int sec)101 arms_sleep(unsigned int sec)
102 {
103 	while ((sec = sleep(sec)) > 0)
104 	       ;
105 }
106 
107 
108 /*
109  * API
110  */
111 int
arms_init(distribution_id_t * distid,arms_context_t ** ctxp)112 arms_init(distribution_id_t *distid, arms_context_t **ctxp)
113 {
114 	static const struct timeval default_app_evt_timo = { 60, 0 };
115 	static const char *ls_urls[] = {
116 		"https://202.221.49.106/arms.cgi",
117 		"https://202.221.51.6/arms.cgi",
118 		"https://[2001:240:bb88::2]/arms.cgi",
119 		"https://[2001:240:bb88::6]/arms.cgi",
120 		NULL
121 	};
122 	arms_context_t *res;
123 	struct _rand_seed {
124 		distribution_id_t distid;
125 		struct timeval tv;
126 	} rand_seed;
127 	int i;
128 
129 	if (distid == NULL) {
130 		return ARMS_EINVAL;
131 	}
132 #ifdef ARMS_DEBUG
133 	printf("Initialize ARMS library\n");
134 	arms_malloc_init();
135 #endif
136 
137 	*ctxp = res = arms_alloc_context();
138 	if (res == NULL) {
139 		return ARMS_ESYSTEM;
140 	}
141 
142 	SSL_load_error_strings();
143 	SSL_library_init();
144 
145 	rand_seed.distid = *distid;
146 	gettimeofday(&rand_seed.tv, NULL);
147 #ifdef HAVE_SRANDOM
148 	srandom(rand_seed.tv.tv_sec ^ rand_seed.tv.tv_usec);
149 #endif
150 	arms_ssl_register_randomness((char *)&rand_seed, sizeof(rand_seed));
151 
152 
153 	/* Initialize resource data */
154 	res->trigger = NULL;
155 	res->lsconf = NULL;
156 	res->cur_method = ARMS_PUSH_METHOD_UNKNOWN;
157 	memcpy(&res->dist_id, distid, sizeof(res->dist_id));
158 	res->line_af = AF_UNSPEC;
159 	arms_hb_init(&res->hb_ctx, 1024, res->dist_id);
160 
161 	/* Create MI Configuration Store */
162 	res->acmi = acmi_create();
163 	if (res->acmi == NULL) {
164 		return ARMS_EFATAL;
165 	}
166 
167 	/* Load Initial Configuration */
168 	for (i = 0; ls_urls[i] != NULL; i++) {
169 		acmi_set_url(res->acmi, ACMI_CONFIG_RSSOL,
170 			     ls_urls[i], URL_MAX_LEN, i);
171 	}
172 	acmi_set_rmax(res->acmi, ACMI_CONFIG_RSSOL, LS_RETRY_MAX);
173 	acmi_set_rint(res->acmi, ACMI_CONFIG_RSSOL, LS_RETRY_INT);
174 	acmi_set_lltimeout(res->acmi, ACMI_CONFIG_RSSOL, LLTIMEOUT);
175 
176 	arms_method_init();
177 
178 	arms_set_app_event_interval(res, &default_app_evt_timo);
179 #if 0
180 	print_openssl_ciphers();
181 #endif
182 
183 #if 0
184  {
185 	 struct addrinfo hints, *re;
186 	 int s, i;
187 	memset(&hints, 0, sizeof(hints));
188 	hints.ai_flags = AI_PASSIVE;
189 	hints.ai_family = AF_INET;
190 	hints.ai_socktype = SOCK_STREAM;
191 	getaddrinfo(NULL, "8080", &hints, &re);
192 
193 	 for (i = 0; i < 1000; i++) {
194 		 s = socket(re->ai_family, re->ai_socktype, re->ai_protocol);
195 		 printf("s=%d\n", s);
196 		 close(s);
197 	 }
198  }
199 #endif
200 
201 	return 0;
202 }
203 
204 /*
205  * API
206  */
207 int
arms_load_config(arms_context_t * res,const char * encrypted_config,size_t len)208 arms_load_config(arms_context_t *res, const char *encrypted_config, size_t len)
209 {
210 	int i;
211 	char *plain;
212 
213 	if (res == NULL)
214 		return ARMS_EFATAL;
215 
216 #ifdef USE_KEY
217 	plain = decrypt_lsconfig((unsigned char *)encrypted_config, len);
218 #else
219 	plain = strdup(encrypted_config);
220 #endif
221 	if (plain == NULL) {
222 		libarms_log(ARMS_LOG_EINITIAL_CONFIG,
223 			    "initial config decrypt error.");
224 		return ARMS_EINVAL;
225 	}
226 
227 	/* len is encrypted len.   plain length is ...??? */
228 	res->lsconf = parse_lsconfig(plain, len);
229 	if (res->lsconf == NULL) {
230 		libarms_log(ARMS_LOG_EINITIAL_CONFIG,
231 			    "initial config parse error.");
232 		free(plain);
233 		return ARMS_EINVAL;
234 	}
235 	free(plain);
236 #if defined(ARMS_DEBUG) && defined(DEBUG_ENABLE)
237 	print_lsconfig(res->lsconf);
238 #endif
239 	acmi_clear(res->acmi, ACMI_CONFIG_RSSOL);
240 	for (i = 0; i < res->lsconf->num_url; i++) {
241 		if (res->lsconf->url[i] == NULL)
242 			break;
243 		acmi_set_url(res->acmi, ACMI_CONFIG_RSSOL,
244 				res->lsconf->url[i], URL_MAX_LEN, i);
245 	}
246 	acmi_set_rmax(res->acmi, ACMI_CONFIG_RSSOL, res->lsconf->retry_max);
247 	acmi_set_rint(res->acmi, ACMI_CONFIG_RSSOL, res->lsconf->retry_int);
248 	acmi_set_lltimeout(res->acmi, ACMI_CONFIG_RSSOL, LLTIMEOUT);
249 	acmi_set_anonpppoe(res->acmi, ACMI_CONFIG_RSSOL,
250 			   res->lsconf->anonid, res->lsconf->anonpass);
251 	acmi_set_anonmobile(res->acmi, ACMI_CONFIG_RSSOL,
252 			    res->lsconf->telno, res->lsconf->cid,
253 			    res->lsconf->apn, res->lsconf->pdp_type,
254 			    res->lsconf->pppid, res->lsconf->ppppass);
255 
256 #if defined(ARMS_DEBUG) && defined (DEBUG_ENABLE)
257 	acmi_dump(res->acmi);
258 #endif
259 
260 	return 0;
261 }
262 
263 /*
264  * API
265  */
266 int
arms_register_cert(arms_context_t * res,const char * root_ca_cert)267 arms_register_cert(arms_context_t *res, const char *root_ca_cert)
268 {
269 	int err;
270 
271 	if (res == NULL)
272 		return ARMS_EFATAL;
273 
274 	if (root_ca_cert == NULL)
275 		return ARMS_EINVAL;
276 
277 	strlcpy(res->root_ca_cert, root_ca_cert, ARMS_MAX_PEM_LEN);
278 
279 #ifdef ARMS_DEBUG
280 	printf("ROOT CA CERT\n");
281 	printf("%s", res->root_ca_cert);
282 #endif
283 	err = arms_ssl_register_cacert(res->root_ca_cert);
284 	if (err != 0) {
285 		return ARMS_EINVAL;
286 	}
287 
288 	return 0;
289 }
290 
291 /*
292  * API
293  */
294 int
arms_register_description(arms_context_t * res,const char * description,const char * version)295 arms_register_description(arms_context_t *res,
296 			  const char *description, const char *version)
297 {
298 	if (res == NULL)
299 		return ARMS_EFATAL;
300 
301 	if (description != NULL) {
302 		if (strlen(description) > ARMS_MAX_DESC_LEN) {
303 			return ARMS_EINVAL;
304 		}
305 		strlcpy(res->description, description,
306 			sizeof(res->description));
307 	}
308 	if (version != NULL) {
309 		if (strlen(version) > ARMS_MAX_VER_LEN) {
310 			return ARMS_EINVAL;
311 		}
312 		strlcpy(res->version, version, sizeof(res->version));
313 	}
314 
315 	return 0;
316 }
317 
318 int
arms_register_authkey(arms_context_t * res,const char * key)319 arms_register_authkey(arms_context_t *res, const char *key)
320 {
321 	if (strlen(key) > 64)
322 		return ARMS_EINVAL;
323 	strlcpy(res->ls_preshared_key, key, sizeof(res->ls_preshared_key));
324 	return 0;
325 }
326 
327 /*
328  * API
329  * 2.20
330  */
331 int
arms_get_rsinfo(arms_context_t * res,arms_rs_info_t * rsp,int size)332 arms_get_rsinfo(arms_context_t *res, arms_rs_info_t *rsp, int size)
333 {
334 	int n = -1;
335 
336 	if (res == (arms_context_t*)0) {
337 	/* error: invalid value */
338 		n = -1;
339 	}
340 	else if (rsp == (arms_rs_info_t*)0) {
341 	/* error: invalid value */
342 		n = -1;
343 	}
344 	else if (size < sizeof(arms_rs_info_t)) {
345 	/* error: too small */
346 		n = -1;
347 	}
348 	else {
349 		for (n = 0; n < MAX_RS_INFO; n++) {
350 			if (res->rs_push_address[n] == NULL) {
351 			/* reach to end of date */
352 				break;
353 			}
354 			if (sizeof(arms_rs_info_t) * (n + 1) > size) {
355 			/* skip: no more buffer */
356 				continue;
357 			}
358 			rsp[n].host = res->rs_push_address[n];
359 		}
360 	}
361 
362 	return n;
363 }
364 
365 /*
366  * free information allocated by conf-sol
367  */
368 void
arms_free_rsinfo(arms_context_t * res)369 arms_free_rsinfo(arms_context_t *res)
370 {
371 	int i;
372 
373 	for (i = 0; i < MAX_RS_INFO; i++) {
374 		if (res->rs_push_address[i] != NULL)
375 			FREE(res->rs_push_address[i]);
376 	}
377 	for (i = 0; i < MAX_RS_INFO; i++) {
378 		if (res->rs_pull_url[i] != NULL)
379 			FREE(res->rs_pull_url[i]);
380 	}
381 }
382 
383 /*
384  * API
385  * 2.20
386  */
387 int
arms_get_proposed_push_port(arms_context_t * res)388 arms_get_proposed_push_port(arms_context_t *res)
389 {
390 	return res->proposed_push_port;
391 }
392 
393 /*
394  * API
395  * 2.20
396  */
397 int
arms_get_proposed_push_timeout(arms_context_t * res)398 arms_get_proposed_push_timeout(arms_context_t *res)
399 {
400 	return res->proposed_push_timeout;
401 }
402 
403 /*
404  * API
405  */
406 int
arms_get_hbtinfo(arms_context_t * res,arms_hbt_info_t * hbp,int size)407 arms_get_hbtinfo(arms_context_t *res, arms_hbt_info_t *hbp, int size)
408 {
409 	int	n = -1;
410 
411 	if (res == (arms_context_t*)0) {
412 	/* error: invalid value */
413 		n = -1;
414 	}
415 	else if (hbp == (arms_hbt_info_t*)0) {
416 	/* error: invalid value */
417 		n = -1;
418 	}
419 	else if (size < 0 || size < sizeof(res->hbt_info[0])) {
420 	/* error: too small */
421 		n = -1;
422 	}
423 	else {
424 		for (n = 0; n < MAX_HBT_INFO; n++) {
425 			if (res->hbt_info[n].host == NULL) {
426 			/* reach to end of date */
427 				break;
428 			}
429 			if (sizeof(arms_hbt_info_t) * (n + 1) > size) {
430 			/* skip: no more buffer */
431 				continue;
432 			}
433 			memcpy(&(hbp[n]), &(res->hbt_info[n]), sizeof(arms_hbt_info_t));
434 		}
435 	}
436 
437 	return n;
438 }
439 
440 void
arms_free_hbtinfo(arms_context_t * res)441 arms_free_hbtinfo(arms_context_t *res)
442 {
443 	int i;
444 
445 	for (i = 0; i < res->num_of_hbt; i++) {
446 		int j;
447 		arms_hbt_info_t *hbp;
448 
449 		hbp = &res->hbt_info[i];
450 		FREE((void *)hbp->host);
451 		FREE((void *)hbp->passphrase);
452 		for (j = 0; j < hbp->numalg; j++) {
453 			FREE((void *)hbp->algorithm[j]);
454 		}
455 	}
456 	res->num_of_hbt = 0;
457 }
458 
459 /*
460  * API
461  */
462 int
arms_get_rs_url(arms_context_t * res,arms_url_t * urlp,int size)463 arms_get_rs_url(arms_context_t *res, arms_url_t *urlp, int size)
464 {
465 	int	n = 0;
466 
467 	if (res == (arms_context_t*)0) {
468 	/* error: invalid value */
469 		n = -1;
470 	}
471 	else if (urlp == (arms_url_t*)0) {
472 	/* error: invalid value */
473 		n = -1;
474 	}
475 	else if (size < sizeof(arms_url_t)) {
476 	/* error: too small */
477 		n = -1;
478 	}
479 	else {
480 		for (n = 0; n < MAX_RS_INFO; n++) {
481 			if (res->rs_pull_url[n] == NULL) {
482 			/* reach to end of date */
483 				break;
484 			}
485 			if (sizeof(arms_url_t) * (n + 1) > size) {
486 			/* skip: no more buffer */
487 				continue;
488 			}
489 			urlp[n].url = res->rs_pull_url[n];
490 		}
491 	}
492 
493 	return n;
494 }
495 
496 /*
497  * API
498  */
499 int
arms_get_rs_tunnel_url(arms_context_t * res,arms_url_t * urlp,int size)500 arms_get_rs_tunnel_url(arms_context_t *res, arms_url_t *urlp, int size)
501 {
502 	int n;
503 
504 	if (res == (arms_context_t*)0) {
505 	/* error: invalid value */
506 		n = -1;
507 	}
508 	else if (urlp == (arms_url_t*)0) {
509 	/* error: invalid value */
510 		n = -1;
511 	}
512 	else if (size < sizeof(arms_url_t)) {
513 	/* error: too small */
514 		n = -1;
515 	}
516 	else {
517 		for (n = 0; n < MAX_RS_INFO; n++) {
518 			if (res->rs_tunnel_url[n] == NULL) {
519 			/* reach to end of date */
520 				break;
521 			}
522 			if (sizeof(arms_rs_info_t) * (n + 1) > size) {
523 			/* skip: no more buffer */
524 				continue;
525 			}
526 			urlp[n].url = res->rs_tunnel_url[n];
527 		}
528 	}
529 
530 	return n;
531 }
532 
533 /*
534  * free tunnel url
535  */
536 void
arms_free_rs_tunnel_url(arms_context_t * res)537 arms_free_rs_tunnel_url(arms_context_t *res)
538 {
539 	int i;
540 
541 	for (i = 0; i < MAX_RS_INFO; i++) {
542 		if (res->rs_tunnel_url[i] != NULL) {
543 			FREE(res->rs_tunnel_url[i]);
544 			res->rs_tunnel_url[i] = NULL;
545 		}
546 	}
547 }
548 
549 /*
550  * API
551  */
552 int
arms_set_pull_trigger(arms_context_t * res,int trigger)553 arms_set_pull_trigger(arms_context_t *res, int trigger)
554 {
555 	static const struct {
556 		int trigger;
557 		char *string;
558 	} trig[] = {
559 		{ ARMS_TRIGGER_CONFIG_ERROR, "invalid config", },
560 		{ ARMS_TRIGGER_SYNC_FAILED,  "module sync failed", },
561 	};
562 	int i;
563 
564 	for (i = 0; i < sizeof(trig) / sizeof(trig[0]); i++) {
565 		if (trig[i].trigger == trigger) {
566 			res->trigger = trig[i].string;
567 			return 0;
568 		}
569 	}
570 	/* invalid trigger */
571 	return -1;
572 }
573 
574 /*
575  * API
576  */
577 int
arms_get_connection_info(arms_context_t * res,arms_connection_info_t * info,int size)578 arms_get_connection_info(arms_context_t *res,
579 			 arms_connection_info_t *info,
580 			 int size)
581 {
582 	struct ssltunnel *tunnel;
583 
584 	if (res == NULL || info == NULL) {
585 		return -1;
586 	}
587 
588 	if (size != sizeof(arms_connection_info_t)) {
589 		return -1;
590 	}
591 
592 	/* connection type: simple or tunnel */
593 	info->method = res->cur_method;
594 
595 	/* protocol info */
596 	info->af = res->sa_af;
597 
598 	/* endpoint address and port */
599 	if (info->method == ARMS_PUSH_METHOD_SIMPLE) {
600 		strlcpy(info->un.simple_info.sa_address,
601 			res->push_endpoint,
602 			sizeof(info->un.simple_info.sa_address));
603 		info->un.simple_info.sa_port = res->server_port;
604 	}
605 	if (info->method == ARMS_PUSH_METHOD_TUNNEL) {
606 		memset(info->un.tunnel_info, 0, sizeof(info->un.tunnel_info));
607 		LIST_FOREACH(tunnel, get_tunnel_list(), next) {
608 			if (tunnel->num < 0 || tunnel->num >= MAX_RS_INFO)
609 				continue;
610 			info->un.tunnel_info[tunnel->num] = ARMS_TUNNEL_ACTIVE;
611 		}
612 	}
613 
614 	return 0;
615 }
616 
617 /*
618  * API
619  */
620 void
arms_end(arms_context_t * res)621 arms_end(arms_context_t *res)
622 {
623 	/* libarms cleanup */
624 	purge_all_modules();
625 	arms_escape(NULL);
626 
627 	/* OpenSSL cleanup */
628 	CRYPTO_cleanup_all_ex_data();
629 	ERR_free_strings();
630 	ERR_remove_state(0);
631 	EVP_cleanup();
632 
633 	if (res != NULL) {
634 		arms_hb_end(&res->hb_ctx);
635 		arms_free_hbtinfo(res);
636 		arms_free_rsinfo(res);
637 		arms_free_rs_tunnel_url(res);
638 		if (res->lsconf != NULL) {
639 			free_lsconfig(res->lsconf);
640 			res->lsconf = NULL;
641 		}
642 
643 		if (res->acmi != NULL) {
644 			acmi_destroy(res->acmi);
645 			res->acmi = NULL;
646 		}
647 		free_arms_method_table();
648 #ifndef ARMS_DEBUG
649 		/*
650 		 * in ARMS_DEBUG case, FREEALL() call log_cb in res.
651 		 * don't free it.
652 		 */
653 		arms_free_context();
654 #endif
655 	}
656 	/* for debug malloc */
657 	FREEALL();
658 }
659 
660 char *
strdistid(distribution_id_t * src)661 strdistid(distribution_id_t *src)
662 {
663 	static char string[MAX_DISTIDSTR + 1];
664 	int err;
665 
666 	if (src == NULL) return NULL;
667 
668 	memset(string, 0, sizeof(string));
669 	err = distid2str(src, string, MAX_DISTIDSTR);
670 	if (err < 0) {
671 		return NULL;
672 	}
673 
674 	return string;
675 }
676 
677 int
distid2str(distribution_id_t * src,char * dst,int len)678 distid2str(distribution_id_t *src, char *dst, int len)
679 {
680 	if (len < 40)           /* strlen(distid) = 39, and 1 for NUL */
681 		return -1;
682 
683 	snprintf(dst, len, "%04X-%04X-%04X-%04X-%04X-%04X-%04X-%04X",
684 
685 		/* version (16bit) */
686 		src->version & 0xffff,
687 
688 		/* vendor (32bit) */
689 		(src->vendor_code >> 16) & 0xffff,
690 		src->vendor_code & 0xffff,
691 
692 		/* sa_type (16bit) */
693 		src->sa_type & 0xffff,
694 
695 		/* sa_code (64bit) */
696 		(unsigned int)((src->sa_code >> 48) & 0xffff),
697 		(unsigned int)((src->sa_code >> 32) & 0xffff),
698 		(unsigned int)((src->sa_code >> 16) & 0xffff),
699 		(unsigned int)(src->sa_code & 0xffff));
700 
701 	return 0;
702 }
703