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