2 * Asterisk -- A telephony toolkit for Linux.
4 * Provide Open Settlement Protocol capability
6 * Copyright (C) 2004, Digium, Inc.
8 * Mark Spencer <markster@digium.com>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
14 #include <sys/types.h>
15 #include <asterisk/file.h>
16 #include <asterisk/channel.h>
17 #include <asterisk/logger.h>
18 #include <asterisk/say.h>
19 #include <asterisk/module.h>
20 #include <asterisk/options.h>
21 #include <asterisk/crypto.h>
22 #include <asterisk/md5.h>
23 #include <asterisk/cli.h>
24 #include <asterisk/io.h>
25 #include <asterisk/lock.h>
26 #include <asterisk/astosp.h>
27 #include <asterisk/config.h>
28 #include <asterisk/utils.h>
29 #include <asterisk/lock.h>
30 #include <asterisk/causes.h>
31 #include <asterisk/callerid.h>
33 #include <openssl/err.h>
40 #include "../asterisk.h"
41 #include "../astconf.h"
42 #include <openssl/bio.h>
43 #include <openssl/pem.h>
44 #include <openssl/evp.h>
48 #define MAX_SERVICEPOINTS 10
51 #define OSP_DEFAULT_MAX_CONNECTIONS 20
52 #define OSP_DEFAULT_RETRY_DELAY 0
53 #define OSP_DEFAULT_RETRY_LIMIT 2
54 #define OSP_DEFAULT_TIMEOUT 500
56 static int loadPemCert(unsigned char *FileName, unsigned char *buffer, int *len);
57 static int loadPemPrivateKey(unsigned char *FileName, unsigned char *buffer, int *len);
59 AST_MUTEX_DEFINE_STATIC(osplock);
61 static int initialized = 0;
62 static int hardware = 0;
66 char localpvtkey[OSP_MAX];
67 char localcert[OSP_MAX];
68 char cacerts[MAX_CERTS][OSP_MAX];
70 char servicepoints[MAX_SERVICEPOINTS][OSP_MAX];
78 OSPTPROVHANDLE handle;
79 struct osp_provider *next;
81 static struct osp_provider *providers;
83 static int osp_build(struct ast_config *cfg, char *cat)
85 OSPTCERT TheAuthCert[MAX_CERTS];
86 unsigned char Reqbuf[4096],LocalBuf[4096],AuthBuf[MAX_CERTS][4096];
87 struct ast_variable *v;
88 struct osp_provider *osp;
89 int x,length,errorcode=0;
91 char *cacerts[MAX_CERTS];
92 const char *servicepoints[MAX_SERVICEPOINTS];
93 OSPTPRIVATEKEY privatekey;
95 OSPTCERT *authCerts[MAX_CERTS];
99 ast_mutex_lock(&osplock);
102 if (!strcasecmp(osp->name, cat))
106 ast_mutex_unlock(&osplock);
109 osp = malloc(sizeof(struct osp_provider));
111 ast_log(LOG_WARNING, "Out of memory!\n");
114 memset(osp, 0, sizeof(struct osp_provider));
117 strncpy(osp->name, cat, sizeof(osp->name) - 1);
118 snprintf(osp->localpvtkey, sizeof(osp->localpvtkey), AST_KEY_DIR "/%s-privatekey.pem", cat);
119 snprintf(osp->localcert, sizeof(osp->localpvtkey), AST_KEY_DIR "/%s-localcert.pem", cat);
120 osp->maxconnections=OSP_DEFAULT_MAX_CONNECTIONS;
121 osp->retrydelay = OSP_DEFAULT_RETRY_DELAY;
122 osp->retrylimit = OSP_DEFAULT_RETRY_LIMIT;
123 osp->timeout = OSP_DEFAULT_TIMEOUT;
124 strcpy(osp->source, "");
125 ast_log(LOG_DEBUG, "Building OSP Provider '%s'\n", cat);
126 v = ast_variable_browse(cfg, cat);
128 if (!strcasecmp(v->name, "privatekey")) {
129 if (v->value[0] == '/')
130 strncpy(osp->localpvtkey, v->value, sizeof(osp->localpvtkey) - 1);
132 snprintf(osp->localpvtkey, sizeof(osp->localpvtkey), AST_KEY_DIR "/%s", v->value);
133 } else if (!strcasecmp(v->name, "localcert")) {
134 if (v->value[0] == '/')
135 strncpy(osp->localcert, v->value, sizeof(osp->localcert) - 1);
137 snprintf(osp->localcert, sizeof(osp->localcert), AST_KEY_DIR "/%s", v->value);
138 } else if (!strcasecmp(v->name, "cacert")) {
139 if (osp->cacount < MAX_CERTS) {
140 if (v->value[0] == '/')
141 strncpy(osp->cacerts[osp->cacount], v->value, sizeof(osp->cacerts[0]));
143 snprintf(osp->cacerts[osp->cacount], sizeof(osp->cacerts[0]), AST_KEY_DIR "/%s", v->value);
146 ast_log(LOG_WARNING, "Too many CA Certificates at line %d\n", v->lineno);
147 } else if (!strcasecmp(v->name, "servicepoint")) {
148 if (osp->spcount < MAX_SERVICEPOINTS) {
149 strncpy(osp->servicepoints[osp->spcount], v->value, sizeof(osp->servicepoints[0]));
152 ast_log(LOG_WARNING, "Too many Service points at line %d\n", v->lineno);
153 } else if (!strcasecmp(v->name, "maxconnections")) {
154 if ((sscanf(v->value, "%i", &x) == 1) && (x > 0) && (x <= 1000)) {
155 osp->maxconnections = x;
157 ast_log(LOG_WARNING, "maxconnections should be an integer from 1 to 1000, not '%s' at line %d\n", v->value, v->lineno);
158 } else if (!strcasecmp(v->name, "retrydelay")) {
159 if ((sscanf(v->value, "%i", &x) == 1) && (x >= 0) && (x <= 10)) {
162 ast_log(LOG_WARNING, "retrydelay should be an integer from 0 to 10, not '%s' at line %d\n", v->value, v->lineno);
163 } else if (!strcasecmp(v->name, "retrylimit")) {
164 if ((sscanf(v->value, "%i", &x) == 1) && (x >= 0) && (x <= 100)) {
167 ast_log(LOG_WARNING, "retrylimit should be an integer from 0 to 100, not '%s' at line %d\n", v->value, v->lineno);
168 } else if (!strcasecmp(v->name, "timeout")) {
169 if ((sscanf(v->value, "%i", &x) == 1) && (x >= 200) && (x <= 10000)) {
172 ast_log(LOG_WARNING, "timeout should be an integer from 200 to 10000, not '%s' at line %d\n", v->value, v->lineno);
176 if (osp->cacount < 1) {
177 snprintf(osp->cacerts[osp->cacount], sizeof(osp->cacerts[0]), AST_KEY_DIR "/%s-cacert.pem", cat);
180 for (x=0;x<osp->cacount;x++)
181 cacerts[x] = osp->cacerts[x];
182 for (x=0;x<osp->spcount;x++)
183 servicepoints[x] = osp->servicepoints[x];
185 ast_mutex_lock(&osplock);
187 if (osp->handle > -1) {
188 ast_log(LOG_DEBUG, "Deleting old handle for '%s'\n", osp->name);
189 OSPPProviderDelete(osp->handle, 0);
194 ast_log(LOG_DEBUG, "Loading private key for '%s' (%s)\n", osp->name, osp->localpvtkey);
195 errorcode = loadPemPrivateKey(osp->localpvtkey,Reqbuf,&length);
198 privatekey.PrivateKeyData = Reqbuf;
199 privatekey.PrivateKeyLength = length;
207 ast_log(LOG_DEBUG, "Loading local cert for '%s' (%s)\n", osp->name, osp->localcert);
208 errorcode = loadPemCert(osp->localcert,LocalBuf,&length);
211 localcert.CertData = LocalBuf;
212 localcert.CertDataLength = length;
219 for (i=0;i<osp->cacount;i++)
222 ast_log(LOG_DEBUG, "Loading CA cert %d for '%s' (%s)\n", i + 1, osp->name, osp->cacerts[i]);
223 errorcode = loadPemCert(osp->cacerts[i],AuthBuf[i],&length);
226 TheAuthCert[i].CertData = AuthBuf[i];
227 TheAuthCert[i].CertDataLength = length;
228 authCerts[i] = &(TheAuthCert[i]);
236 ast_log(LOG_DEBUG, "Creating provider handle for '%s'\n", osp->name);
238 ast_log(LOG_DEBUG, "Service point '%s %d'\n", servicepoints[0], osp->spcount);
240 if (OSPPProviderNew(osp->spcount,
247 (const OSPTCERT **)authCerts,
258 ast_log(LOG_WARNING, "Unable to initialize provider '%s'\n", cat);
263 osp->next = providers;
266 ast_mutex_unlock(&osplock);
270 static int show_osp(int fd, int argc, char *argv[])
272 struct osp_provider *osp;
276 if ((argc < 2) || (argc > 3))
277 return RESULT_SHOWUSAGE;
281 ast_cli(fd, "OSP: %s %s\n", initialized ? "Initialized" : "Uninitialized", hardware ? "Accelerated" : "Normal");
283 ast_mutex_lock(&osplock);
286 if (!search || !strcasecmp(osp->name, search)) {
289 ast_cli(fd, " == OSP Provider '%s' ==\n", osp->name);
290 ast_cli(fd, "Local Private Key: %s\n", osp->localpvtkey);
291 ast_cli(fd, "Local Certificate: %s\n", osp->localcert);
292 for (x=0;x<osp->cacount;x++)
293 ast_cli(fd, "CA Certificate %d: %s\n", x + 1, osp->cacerts[x]);
294 for (x=0;x<osp->spcount;x++)
295 ast_cli(fd, "Service Point %d: %s\n", x + 1, osp->servicepoints[x]);
296 ast_cli(fd, "Max Connections: %d\n", osp->maxconnections);
297 ast_cli(fd, "Retry Delay: %d seconds\n", osp->retrydelay);
298 ast_cli(fd, "Retry Limit: %d\n", osp->retrylimit);
299 ast_cli(fd, "Timeout: %d milliseconds\n", osp->timeout);
300 ast_cli(fd, "Source: %s\n", strlen(osp->source) ? osp->source : "<unspecified>");
301 ast_cli(fd, "OSP Handle: %d\n", osp->handle);
306 ast_mutex_unlock(&osplock);
309 ast_cli(fd, "Unable to find OSP provider '%s'\n", search);
311 ast_cli(fd, "No OSP providers configured\n");
313 return RESULT_SUCCESS;
317 /*----------------------------------------------*
318 * Loads the Certificate *
319 *----------------------------------------------*/
320 static int loadPemCert(unsigned char *FileName, unsigned char *buffer, int *len)
326 int retVal = OSPC_ERR_NO_ERROR;
329 bioIn = BIO_new_file((const char*)FileName,"r");
332 ast_log(LOG_WARNING,"Failed to find the File - %s \n",FileName);
337 cert = PEM_read_bio_X509(bioIn,NULL,NULL,NULL);
340 ast_log(LOG_WARNING,"Failed to parse the Certificate from the File - %s \n",FileName);
345 length = i2d_X509(cert,&temp);
348 ast_log(LOG_WARNING,"Failed to parse the Certificate from the File - %s, Length=0 \n",FileName);
370 /*----------------------------------------------*
371 * Loads the Private Key *
372 *----------------------------------------------*/
373 static int loadPemPrivateKey(unsigned char *FileName, unsigned char *buffer, int *len)
379 int retVal = OSPC_ERR_NO_ERROR;
383 bioIn = BIO_new_file((const char*)FileName,"r");
386 ast_log(LOG_WARNING,"Failed to find the File - %s \n",FileName);
391 pKey = PEM_read_bio_RSAPrivateKey(bioIn,NULL,NULL,NULL);
394 ast_log(LOG_WARNING,"Failed to parse the Private Key from the File - %s \n",FileName);
399 length = i2d_RSAPrivateKey(pKey,&temp);
402 ast_log(LOG_WARNING,"Failed to parse the Private Key from the File - %s, Length=0 \n",FileName);
423 int ast_osp_validate(char *provider, char *token, int *handle, unsigned int *timelimit, char *callerid, struct in_addr addr, char *extension)
425 char tmp[256]="", *l, *n;
426 char iabuf[INET_ADDRSTRLEN];
427 char source[OSP_MAX]; /* Same length as osp->source */
430 struct osp_provider *osp;
432 unsigned int authorised, dummy;
434 if (!provider || !strlen(provider))
435 provider = "default";
437 token2 = ast_strdupa(token);
440 tokenlen = ast_base64decode(token2, token, strlen(token));
444 strncpy(tmp, callerid, sizeof(tmp) - 1);
445 ast_callerid_parse(tmp, &n, &l);
449 ast_shrink_phone_number(l);
450 if (!ast_isphonenumber(l))
454 ast_mutex_lock(&osplock);
455 ast_inet_ntoa(iabuf, sizeof(iabuf), addr);
458 if (!strcasecmp(osp->name, provider)) {
459 if (OSPPTransactionNew(osp->handle, handle)) {
460 ast_log(LOG_WARNING, "Unable to create OSP Transaction handle!\n");
462 strcpy(source, osp->source);
469 ast_mutex_unlock(&osplock);
473 if (!OSPPTransactionValidateAuthorisation(*handle, iabuf, source, NULL, NULL,
474 callerid, OSPC_E164, extension, OSPC_E164, 0, "", tokenlen, token2, &authorised, timelimit, &dummy, NULL, TOKEN_ALGO_BOTH)) {
476 ast_log(LOG_DEBUG, "Validated token for '%s' from '%s@%s'\n", extension, callerid, iabuf);
484 int ast_osp_lookup(struct ast_channel *chan, char *provider, char *extension, char *callerid, struct ast_osp_result *result)
490 unsigned int dummy=0;
491 unsigned int timelimit;
492 unsigned int callidlen;
493 struct osp_provider *osp;
494 char source[OSP_MAX]; /* Same length as osp->source */
495 char uniqueid[32] = "";
496 char callednum[2048]="";
497 char destination[2048]="";
499 char tmp[256]="", *l, *n;
504 result->numresults = 0;
505 strcpy(result->tech, "");
506 strcpy(result->dest, "");
507 strcpy(result->token, "");
509 if (!provider || !strlen(provider))
510 provider = "default";
514 strncpy(tmp, callerid, sizeof(tmp) - 1);
515 ast_callerid_parse(tmp, &n, &l);
519 ast_shrink_phone_number(l);
520 if (!ast_isphonenumber(l))
526 strncpy(uniqueid, chan->uniqueid, sizeof(uniqueid) - 1);
527 cres = ast_autoservice_start(chan);
531 ast_mutex_lock(&osplock);
534 if (!strcasecmp(osp->name, provider)) {
535 if (OSPPTransactionNew(osp->handle, &result->handle)) {
536 ast_log(LOG_WARNING, "Unable to create OSP Transaction handle!\n");
538 strcpy(source, osp->source);
545 ast_mutex_unlock(&osplock);
548 callid = OSPPCallIdNew(strlen(uniqueid), uniqueid);
550 /* No more than 10 back */
553 callidlen = sizeof(uniqueid);
554 if (!OSPPTransactionRequestAuthorisation(result->handle, source, "",
555 callerid,OSPC_E164, extension, OSPC_E164, NULL, 1, &callid, NULL, &counts, &dummy, NULL)) {
557 tokenlen = sizeof(token);
558 result->numresults = counts - 1;
559 if (!OSPPTransactionGetFirstDestination(result->handle, 0, NULL, NULL, &timelimit, &callidlen, uniqueid,
560 sizeof(callednum), callednum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) {
561 ast_log(LOG_DEBUG, "Got destination '%s' and '%s' for '%s' (provider '%s')\n",
562 destination, callednum, extension, provider);
564 ast_base64encode(result->token, token, tokenlen, sizeof(result->token) - 1);
565 if ((strlen(destination) > 2) && !OSPPTransactionGetDestProtocol(result->handle, &prot)) {
567 /* Strip leading and trailing brackets */
568 destination[strlen(destination) - 1] = '\0';
570 case OSPE_DEST_PROT_H323_SETUP:
571 strcpy(result->tech, "H323");
572 snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
574 case OSPE_DEST_PROT_SIP:
575 strcpy(result->tech, "SIP");
576 snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
579 ast_log(LOG_DEBUG, "Unknown destination protocol '%d', skipping...\n", prot);
582 if (!res && result->numresults) {
583 result->numresults--;
584 if (OSPPTransactionGetNextDestination(result->handle, OSPC_FAIL_INCOMPATIBLE_DEST, 0, NULL, NULL, &timelimit, &callidlen, uniqueid,
585 sizeof(callednum), callednum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) {
590 ast_log(LOG_DEBUG, "Missing destination protocol\n");
593 } while(!res && result->numresults);
598 OSPPCallIdDelete(&callid);
601 OSPPTransactionDelete(result->handle);
607 ast_log(LOG_NOTICE, "OSP Provider '%s' does not exist!\n", provider);
609 cres = ast_autoservice_stop(chan);
616 int ast_osp_next(struct ast_osp_result *result, int cause)
620 unsigned int dummy=0;
621 unsigned int timelimit;
622 unsigned int callidlen;
623 char uniqueid[32] = "";
624 char callednum[2048]="";
625 char destination[2048]="";
629 strcpy(result->tech, "");
630 strcpy(result->dest, "");
631 strcpy(result->token, "");
633 if (result->handle > -1) {
635 callidlen = sizeof(uniqueid);
636 if (result->numresults) {
637 tokenlen = sizeof(token);
638 while(!res && result->numresults) {
639 result->numresults--;
640 if (!OSPPTransactionGetNextDestination(result->handle, OSPC_FAIL_INCOMPATIBLE_DEST, 0, NULL, NULL, &timelimit, &callidlen, uniqueid,
641 sizeof(callednum), callednum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) {
642 ast_base64encode(result->token, token, tokenlen, sizeof(result->token) - 1);
643 if ((strlen(destination) > 2) && !OSPPTransactionGetDestProtocol(result->handle, &prot)) {
645 /* Strip leading and trailing brackets */
646 destination[strlen(destination) - 1] = '\0';
648 case OSPE_DEST_PROT_H323_SETUP:
649 strcpy(result->tech, "H323");
650 snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
652 case OSPE_DEST_PROT_SIP:
653 strcpy(result->tech, "SIP");
654 snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
657 ast_log(LOG_DEBUG, "Unknown destination protocol '%d', skipping...\n", prot);
661 ast_log(LOG_DEBUG, "Missing destination protocol\n");
669 OSPPTransactionDelete(result->handle);
677 static enum OSPEFAILREASON cause2reason(int cause)
681 return OSPC_FAIL_USER_BUSY;
682 case AST_CAUSE_CONGESTION:
683 return OSPC_FAIL_SWITCHING_EQUIPMENT_CONGESTION;
684 case AST_CAUSE_UNALLOCATED:
685 return OSPC_FAIL_UNALLOC_NUMBER;
686 case AST_CAUSE_NOTDEFINED:
687 return OSPC_FAIL_NORMAL_UNSPECIFIED;
688 case AST_CAUSE_NOANSWER:
689 return OSPC_FAIL_NO_ANSWER_FROM_USER;
690 case AST_CAUSE_NORMAL:
692 return OSPC_FAIL_NORMAL_CALL_CLEARING;
696 int ast_osp_terminate(int handle, int cause, time_t start, time_t duration)
698 unsigned int dummy = 0;
700 enum OSPEFAILREASON reason;
701 reason = cause2reason(cause);
702 if (OSPPTransactionRecordFailure(handle, reason))
703 ast_log(LOG_WARNING, "Failed to record call termination for handle %d\n", handle);
704 else if (OSPPTransactionReportUsage(handle, duration, start, 0, 0, 0, 0, &dummy, NULL))
705 ast_log(LOG_WARNING, "Failed to report duration for handle %d\n", handle);
707 ast_log(LOG_DEBUG, "Completed recording handle %d\n", handle);
708 OSPPTransactionDelete(handle);
714 static int config_load(void)
716 struct ast_config *cfg;
718 struct osp_provider *osp, *prev = NULL, *next;
719 ast_mutex_lock(&osplock);
725 ast_mutex_unlock(&osplock);
726 cfg = ast_load("osp.conf");
729 cat = ast_variable_retrieve(cfg, "general", "accelerate");
730 if (cat && ast_true(cat))
732 ast_log(LOG_WARNING, "Failed to enable hardware accelleration, falling back to software mode\n");
740 cat = ast_category_browse(cfg, NULL);
742 if (strcasecmp(cat, "general"))
744 cat = ast_category_browse(cfg, cat);
748 ast_log(LOG_NOTICE, "No OSP configuration found. OSP support disabled\n");
749 ast_mutex_lock(&osplock);
758 /* XXX Cleanup OSP structure first XXX */
764 ast_mutex_unlock(&osplock);
768 static char show_osp_usage[] =
770 " Displays information on Open Settlement Protocol\n";
772 static struct ast_cli_entry cli_show_osp =
773 { { "show", "osp", NULL }, show_osp, "Displays OSP information", show_osp_usage };
778 ast_log(LOG_NOTICE, "XXX Should reload OSP config XXX\n");
782 int load_module(void)
785 ast_cli_register(&cli_show_osp);
789 int unload_module(void)
791 /* Can't unload this once we're loaded */
795 char *description(void)
797 return "Open Settlement Protocol Support";
802 /* We should never be unloaded */
808 return ASTERISK_GPL_KEY;