128befbcc1f33fe4ff16358522b2d217c8d05cfd
[asterisk/asterisk.git] / res / res_osp.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*
20  *
21  * Provide Open Settlement Protocol capability
22  * 
23  */
24
25 #include <sys/types.h>
26 #include <osp.h>
27 #include <openssl/err.h>
28 #include <stdio.h>
29 #include <dirent.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <openssl/bio.h>
35 #include <openssl/pem.h>
36 #include <openssl/evp.h>
37
38 #include "asterisk.h"
39
40 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
41
42 #include "asterisk/file.h"
43 #include "asterisk/channel.h"
44 #include "asterisk/logger.h"
45 #include "asterisk/say.h"
46 #include "asterisk/module.h"
47 #include "asterisk/options.h"
48 #include "asterisk/crypto.h"
49 #include "asterisk/md5.h"
50 #include "asterisk/cli.h"
51 #include "asterisk/io.h"
52 #include "asterisk/lock.h"
53 #include "asterisk/astosp.h"
54 #include "asterisk/config.h"
55 #include "asterisk/utils.h"
56 #include "asterisk/lock.h"
57 #include "asterisk/causes.h"
58 #include "asterisk/callerid.h"
59 #include "asterisk/pbx.h"
60
61 #define MAX_CERTS 10
62 #define MAX_SERVICEPOINTS 10
63 #define OSP_MAX 256
64
65 #define OSP_DEFAULT_MAX_CONNECTIONS     20
66 #define OSP_DEFAULT_RETRY_DELAY         0
67 #define OSP_DEFAULT_RETRY_LIMIT         2
68 #define OSP_DEFAULT_TIMEOUT                     500
69
70 static int loadPemCert(unsigned char *FileName, unsigned char *buffer, int *len);
71 static int loadPemPrivateKey(unsigned char *FileName, unsigned char *buffer, int *len);
72
73 AST_MUTEX_DEFINE_STATIC(osplock);
74
75 static int initialized = 0;
76 static int hardware = 0;
77 static unsigned tokenformat = TOKEN_ALGO_SIGNED;
78
79 struct osp_provider {
80         char name[OSP_MAX];
81         char localpvtkey[OSP_MAX];
82         char localcert[OSP_MAX];
83         char cacerts[MAX_CERTS][OSP_MAX]; 
84         int cacount;
85         char servicepoints[MAX_SERVICEPOINTS][OSP_MAX];
86         char source[OSP_MAX];
87         int spcount;
88         int dead;
89         int maxconnections;
90         int retrydelay;
91         int retrylimit;
92         int timeout;
93         OSPTPROVHANDLE handle;
94         struct osp_provider *next;
95 };
96 static struct osp_provider *providers;
97
98 static int osp_build(struct ast_config *cfg, char *cat)
99 {
100         OSPTCERT TheAuthCert[MAX_CERTS];
101         unsigned char Reqbuf[4096],LocalBuf[4096],AuthBuf[MAX_CERTS][4096];
102         struct ast_variable *v;
103         struct osp_provider *osp;
104         int x,length,errorcode=0;
105         int mallocd=0,i;
106         char *cacerts[MAX_CERTS];
107         const char *servicepoints[MAX_SERVICEPOINTS];
108         OSPTPRIVATEKEY privatekey;
109         OSPTCERT localcert;
110         OSPTCERT *authCerts[MAX_CERTS];
111
112         
113         
114         ast_mutex_lock(&osplock);
115         osp = providers;
116         while(osp) {
117                 if (!strcasecmp(osp->name, cat))
118                         break;
119                 osp = osp->next;
120         }
121         ast_mutex_unlock(&osplock);
122         if (!osp) {
123                 mallocd = 1;
124                 osp = malloc(sizeof(struct osp_provider));
125                 if (!osp) {
126                         ast_log(LOG_WARNING, "Out of memory!\n");
127                         return -1;
128                 }
129                 memset(osp, 0, sizeof(struct osp_provider));
130                 osp->handle = -1;
131         }
132         ast_copy_string(osp->name, cat, sizeof(osp->name));
133         snprintf(osp->localpvtkey, sizeof(osp->localpvtkey) ,"%s/%s-privatekey.pem", ast_config_AST_KEY_DIR, cat);
134         snprintf(osp->localcert, sizeof(osp->localpvtkey), "%s/%s-localcert.pem", ast_config_AST_KEY_DIR, cat);
135         osp->maxconnections=OSP_DEFAULT_MAX_CONNECTIONS;
136         osp->retrydelay = OSP_DEFAULT_RETRY_DELAY;
137         osp->retrylimit = OSP_DEFAULT_RETRY_LIMIT;
138         osp->timeout = OSP_DEFAULT_TIMEOUT;
139         osp->source[0] = '\0';
140         ast_log(LOG_DEBUG, "Building OSP Provider '%s'\n", cat);
141         v = ast_variable_browse(cfg, cat);
142         while(v) {
143                 if (!strcasecmp(v->name, "privatekey")) {
144                         if (v->value[0] == '/')
145                                 ast_copy_string(osp->localpvtkey, v->value, sizeof(osp->localpvtkey));
146                         else
147                                 snprintf(osp->localpvtkey, sizeof(osp->localpvtkey), "%s/%s", ast_config_AST_KEY_DIR , v->value);
148                 } else if (!strcasecmp(v->name, "localcert")) {
149                         if (v->value[0] == '/')
150                                 ast_copy_string(osp->localcert, v->value, sizeof(osp->localcert));
151                         else
152                                 snprintf(osp->localcert, sizeof(osp->localcert), "%s/%s", ast_config_AST_KEY_DIR, v->value);
153                 } else if (!strcasecmp(v->name, "cacert")) {
154                         if (osp->cacount < MAX_CERTS) {
155                                 if (v->value[0] == '/')
156                                         ast_copy_string(osp->cacerts[osp->cacount], v->value, sizeof(osp->cacerts[0]));
157                                 else
158                                         snprintf(osp->cacerts[osp->cacount], sizeof(osp->cacerts[0]), "%s/%s", ast_config_AST_KEY_DIR, v->value);
159                                 osp->cacount++;
160                         } else
161                                 ast_log(LOG_WARNING, "Too many CA Certificates at line %d\n", v->lineno);
162                 } else if (!strcasecmp(v->name, "servicepoint")) {
163                         if (osp->spcount < MAX_SERVICEPOINTS) {
164                                 ast_copy_string(osp->servicepoints[osp->spcount], v->value, sizeof(osp->servicepoints[0]));
165                                 osp->spcount++;
166                         } else
167                                 ast_log(LOG_WARNING, "Too many Service points at line %d\n", v->lineno);
168                 } else if (!strcasecmp(v->name, "maxconnections")) {
169                         if ((sscanf(v->value, "%d", &x) == 1) && (x > 0) && (x <= 1000)) {
170                                 osp->maxconnections = x;
171                         } else
172                                 ast_log(LOG_WARNING, "maxconnections should be an integer from 1 to 1000, not '%s' at line %d\n", v->value, v->lineno);
173                 } else if (!strcasecmp(v->name, "retrydelay")) {
174                         if ((sscanf(v->value, "%d", &x) == 1) && (x >= 0) && (x <= 10)) {
175                                 osp->retrydelay = x;
176                         } else
177                                 ast_log(LOG_WARNING, "retrydelay should be an integer from 0 to 10, not '%s' at line %d\n", v->value, v->lineno);
178                 } else if (!strcasecmp(v->name, "retrylimit")) {
179                         if ((sscanf(v->value, "%d", &x) == 1) && (x >= 0) && (x <= 100)) {
180                                 osp->retrylimit = x;
181                         } else
182                                 ast_log(LOG_WARNING, "retrylimit should be an integer from 0 to 100, not '%s' at line %d\n", v->value, v->lineno);
183                 } else if (!strcasecmp(v->name, "timeout")) {
184                         if ((sscanf(v->value, "%d", &x) == 1) && (x >= 200) && (x <= 10000)) {
185                                 osp->timeout = x;
186                         } else
187                                 ast_log(LOG_WARNING, "timeout should be an integer from 200 to 10000, not '%s' at line %d\n", v->value, v->lineno);
188                 } else if (!strcasecmp(v->name, "source")) {
189                         ast_copy_string(osp->source, v->value, sizeof(osp->source));
190                 }
191                 v = v->next;
192         }
193         if (osp->cacount < 1) {
194                 snprintf(osp->cacerts[osp->cacount], sizeof(osp->cacerts[0]), "%s/%s-cacert.pem", ast_config_AST_KEY_DIR, cat);
195                 osp->cacount++;
196         }
197         for (x=0;x<osp->cacount;x++)
198                 cacerts[x] = osp->cacerts[x];
199         for (x=0;x<osp->spcount;x++)
200                 servicepoints[x] = osp->servicepoints[x];
201         
202         ast_mutex_lock(&osplock);
203         osp->dead = 0;
204         if (osp->handle > -1) {
205                 ast_log(LOG_DEBUG, "Deleting old handle for '%s'\n", osp->name);
206                 OSPPProviderDelete(osp->handle, 0);
207         }
208                 
209
210     length = 0;
211         ast_log(LOG_DEBUG, "Loading private key for '%s' (%s)\n", osp->name, osp->localpvtkey);
212     errorcode = loadPemPrivateKey(osp->localpvtkey,Reqbuf,&length);
213     if (errorcode == 0)
214     {
215         privatekey.PrivateKeyData = Reqbuf;
216         privatekey.PrivateKeyLength = length;
217     }
218     else
219     {
220          return -1;
221     }
222
223     length = 0;
224         ast_log(LOG_DEBUG, "Loading local cert for '%s' (%s)\n", osp->name, osp->localcert);
225     errorcode = loadPemCert(osp->localcert,LocalBuf,&length);
226     if (errorcode == 0)
227     {
228         localcert.CertData = LocalBuf;
229         localcert.CertDataLength = length;
230     }
231     else
232     {
233          return -1;
234     }
235
236     for (i=0;i<osp->cacount;i++)
237     {
238         length = 0;
239                 ast_log(LOG_DEBUG, "Loading CA cert %d for '%s' (%s)\n", i + 1, osp->name, osp->cacerts[i]);
240         errorcode = loadPemCert(osp->cacerts[i],AuthBuf[i],&length);
241         if (errorcode == 0)
242         {
243             TheAuthCert[i].CertData = AuthBuf[i];
244             TheAuthCert[i].CertDataLength = length;
245             authCerts[i] = &(TheAuthCert[i]);
246         }
247         else
248         {
249                         return -1;        
250                 }
251     }
252         
253         ast_log(LOG_DEBUG, "Creating provider handle for '%s'\n", osp->name);
254         
255         ast_log(LOG_DEBUG, "Service point '%s %d'\n", servicepoints[0], osp->spcount);
256         
257         if (OSPPProviderNew(osp->spcount, 
258                                             servicepoints, 
259                                            NULL, 
260                                            "localhost", 
261                                            &privatekey, 
262                                            &localcert, 
263                                            osp->cacount, 
264                                            (const OSPTCERT **)authCerts, 
265                                            1, 
266                                            300, 
267                                            osp->maxconnections, 
268                                            1, 
269                                            osp->retrydelay, 
270                                            osp->retrylimit, 
271                                            osp->timeout, 
272                                            "", 
273                                            "", 
274                                            &osp->handle)) {
275                 ast_log(LOG_WARNING, "Unable to initialize provider '%s'\n", cat);
276                 osp->dead = 1;
277         }
278         
279         if (mallocd) {
280                 osp->next = providers;
281                 providers = osp;
282         }
283         ast_mutex_unlock(&osplock);     
284         return 0;
285 }
286
287 static int show_osp(int fd, int argc, char *argv[])
288 {
289         struct osp_provider *osp;
290         char *search = NULL;
291         int x;
292         int found = 0;
293         char *tokenalgo;
294
295         if ((argc < 2) || (argc > 3))
296                 return RESULT_SHOWUSAGE;
297         if (argc > 2)
298                 search = argv[2];
299         if (!search) {
300                 switch (tokenformat) {
301                         case TOKEN_ALGO_BOTH:
302                                 tokenalgo = "Both";
303                                 break;
304                         case TOKEN_ALGO_UNSIGNED:
305                                 tokenalgo = "Unsigned";
306                                 break;
307                         case TOKEN_ALGO_SIGNED:
308                         default:
309                                 tokenalgo = "Signed";
310                                 break;
311                 }
312                 ast_cli(fd, "OSP: %s %s %s\n", initialized ? "Initialized" : "Uninitialized", hardware ? "Accelerated" : "Normal", tokenalgo);
313         }
314
315         ast_mutex_lock(&osplock);
316         osp = providers;
317         while(osp) {
318                 if (!search || !strcasecmp(osp->name, search)) {
319                         if (found)
320                                 ast_cli(fd, "\n");
321                         ast_cli(fd, " == OSP Provider '%s' ==\n", osp->name);
322                         ast_cli(fd, "Local Private Key: %s\n", osp->localpvtkey);
323                         ast_cli(fd, "Local Certificate: %s\n", osp->localcert);
324                         for (x=0;x<osp->cacount;x++)
325                                 ast_cli(fd, "CA Certificate %d:  %s\n", x + 1, osp->cacerts[x]);
326                         for (x=0;x<osp->spcount;x++)
327                                 ast_cli(fd, "Service Point %d:   %s\n", x + 1, osp->servicepoints[x]);
328                         ast_cli(fd, "Max Connections:   %d\n", osp->maxconnections);
329                         ast_cli(fd, "Retry Delay:       %d seconds\n", osp->retrydelay);
330                         ast_cli(fd, "Retry Limit:       %d\n", osp->retrylimit);
331                         ast_cli(fd, "Timeout:           %d milliseconds\n", osp->timeout);
332                         ast_cli(fd, "Source:            %s\n", strlen(osp->source) ? osp->source : "<unspecified>");
333                         ast_cli(fd, "OSP Handle:        %d\n", osp->handle);
334                         found++;
335                 }
336                 osp = osp->next;
337         }
338         ast_mutex_unlock(&osplock);
339         if (!found) {
340                 if (search) 
341                         ast_cli(fd, "Unable to find OSP provider '%s'\n", search);
342                 else
343                         ast_cli(fd, "No OSP providers configured\n");
344         }
345         return RESULT_SUCCESS;
346 }
347
348
349 /*----------------------------------------------*
350  *               Loads the Certificate          *
351  *----------------------------------------------*/
352 static int loadPemCert(unsigned char *FileName, unsigned char *buffer, int *len)
353 {
354     int length = 0;
355     unsigned char *temp;
356     BIO *bioIn = NULL;
357     X509 *cert=NULL;
358     int retVal = OSPC_ERR_NO_ERROR;
359
360     temp = buffer;
361     bioIn = BIO_new_file((const char*)FileName,"r");
362     if (bioIn == NULL)
363     {
364                 ast_log(LOG_WARNING,"Failed to find the File - %s \n",FileName);
365                 return -1;
366     }
367     else
368     {
369         cert = PEM_read_bio_X509(bioIn,NULL,NULL,NULL);
370         if (cert == NULL)
371         {
372                         ast_log(LOG_WARNING,"Failed to parse the Certificate from the File - %s \n",FileName);
373                         return -1;
374         }
375         else
376         {
377             length = i2d_X509(cert,&temp);
378             if (cert == 0)
379             {
380                                 ast_log(LOG_WARNING,"Failed to parse the Certificate from the File - %s, Length=0 \n",FileName);
381                                 return -1;
382             }
383             else
384                         {
385                *len = length;
386             }
387         }
388     }
389
390     if (bioIn != NULL)
391     {
392         BIO_free(bioIn);
393     }
394
395     if (cert != NULL)
396     {
397         X509_free(cert);
398     }
399     return retVal;
400 }
401
402 /*----------------------------------------------*
403  *               Loads the Private Key          *
404  *----------------------------------------------*/
405 static int loadPemPrivateKey(unsigned char *FileName, unsigned char *buffer, int *len)
406 {
407     int length = 0;
408     unsigned char *temp;
409     BIO *bioIn = NULL;
410     RSA *pKey = NULL;
411     int retVal = OSPC_ERR_NO_ERROR;
412
413     temp = buffer;
414
415     bioIn = BIO_new_file((const char*)FileName,"r");
416     if (bioIn == NULL)
417     {
418                 ast_log(LOG_WARNING,"Failed to find the File - %s \n",FileName);
419                 return -1;
420     }
421     else
422     {
423         pKey = PEM_read_bio_RSAPrivateKey(bioIn,NULL,NULL,NULL);
424         if (pKey == NULL)
425         {
426                         ast_log(LOG_WARNING,"Failed to parse the Private Key from the File - %s \n",FileName);
427                         return -1;
428         }
429         else
430         {
431             length = i2d_RSAPrivateKey(pKey,&temp);
432             if (length == 0)
433             {
434                                 ast_log(LOG_WARNING,"Failed to parse the Private Key from the File - %s, Length=0 \n",FileName);
435                                 return -1;
436             }
437             else
438             {
439                 *len = length;
440             }
441         }
442     }
443     if (bioIn != NULL)
444     {
445         BIO_free(bioIn);
446     }
447
448     if (pKey != NULL)
449     {
450        RSA_free(pKey);
451     }
452     return retVal;
453 }
454
455 int ast_osp_validate(char *provider, char *token, int *handle, unsigned int *timelimit, char *callerid, struct in_addr addr, char *extension)
456 {
457         char tmp[256]="", *l, *n;
458         char iabuf[INET_ADDRSTRLEN];
459         char source[OSP_MAX] = ""; /* Same length as osp->source */
460         char *token2;
461         int tokenlen;
462         struct osp_provider *osp;
463         int res = 0;
464         unsigned int authorised, dummy;
465
466         if (!provider || !strlen(provider))
467                 provider = "default";
468
469         token2 = ast_strdupa(token);
470         if (!token2)
471                 return -1;
472         tokenlen = ast_base64decode(token2, token, strlen(token));
473         *handle = -1;
474         if (!callerid)
475                 callerid = "";
476         ast_copy_string(tmp, callerid, sizeof(tmp));
477         ast_callerid_parse(tmp, &n, &l);
478         if (!l)
479                 l = "";
480         else {
481                 ast_shrink_phone_number(l);
482                 if (!ast_isphonenumber(l))
483                         l = "";
484         }
485         callerid = l;
486         ast_mutex_lock(&osplock);
487         ast_inet_ntoa(iabuf, sizeof(iabuf), addr);
488         osp = providers;
489         while(osp) {
490                 if (!strcasecmp(osp->name, provider)) {
491                         if (OSPPTransactionNew(osp->handle, handle)) {
492                                 ast_log(LOG_WARNING, "Unable to create OSP Transaction handle!\n");
493                         } else {
494                                 ast_copy_string(source, osp->source, sizeof(source));
495                                 res = 1;
496                         }
497                         break;
498                 }
499                 osp = osp->next;
500         }
501         ast_mutex_unlock(&osplock);
502         if (res) {
503                 res = 0;
504                 dummy = 0;
505                 if (!OSPPTransactionValidateAuthorisation(*handle, iabuf, source, NULL, NULL, 
506                         callerid, OSPC_E164, extension, OSPC_E164, 0, "", tokenlen, token2, &authorised, timelimit, &dummy, NULL, tokenformat)) {
507                         if (authorised) {
508                                 ast_log(LOG_DEBUG, "Validated token for '%s' from '%s@%s'\n", extension, callerid, iabuf);
509                                 res = 1;
510                         }
511                 }
512         }
513         return res;     
514 }
515
516 int ast_osp_lookup(struct ast_channel *chan, char *provider, char *extension, char *callerid, struct ast_osp_result *result)
517 {
518         int cres;
519         int res = 0;
520         int counts;
521         int tokenlen;
522         unsigned int dummy=0;
523         unsigned int timelimit;
524         char* sipcallid;
525         unsigned int callidlen;
526         char callidstr[OSPC_CALLID_MAXSIZE] = "";
527         struct osp_provider *osp;
528         char source[OSP_MAX] = ""; /* Same length as osp->source */
529         char callednum[2048]="";
530         char callingnum[2048]="";
531         char destination[2048]="";
532         char token[2000];
533         char tmp[256]="", *l, *n;
534         OSPTCALLID *callid;
535         OSPE_DEST_PROT prot;
536         OSPE_DEST_OSP_ENABLED ospenabled;
537
538         result->handle = -1;
539         result->numresults = 0;
540         result->tech[0] = '\0';
541         result->dest[0] = '\0';
542         result->token[0] = '\0';
543
544         if (!provider || !strlen(provider))
545                 provider = "default";
546
547         if (!callerid)
548                 callerid = "";
549         ast_copy_string(tmp, callerid, sizeof(tmp));
550         ast_callerid_parse(tmp, &n, &l);
551         if (!l)
552                 l = "";
553         else {
554                 ast_shrink_phone_number(l);
555                 if (!ast_isphonenumber(l))
556                         l = "";
557         }
558         callerid = l;
559
560         if (chan) {
561                 sipcallid = pbx_builtin_getvar_helper (chan, "SIPCALLID");
562                 ast_copy_string(callidstr, sipcallid, sizeof(callidstr));
563                 cres = ast_autoservice_start(chan);
564                 if (cres < 0)
565                         return cres;
566         }
567         ast_mutex_lock(&osplock);
568         osp = providers;
569         while(osp) {
570                 if (!strcasecmp(osp->name, provider)) {
571                         if (OSPPTransactionNew(osp->handle, &result->handle)) {
572                                 ast_log(LOG_WARNING, "Unable to create OSP Transaction handle!\n");
573                         } else {
574                                 ast_copy_string(source, osp->source, sizeof(source));
575                                 res = 1;
576                         }
577                         break;
578                 }
579                 osp = osp->next;
580         }
581         ast_mutex_unlock(&osplock);
582         if (res) {
583                 res = 0;
584                 callid = OSPPCallIdNew(strlen(callidstr), callidstr);
585                 if (callid) {
586                         /* No more than 10 back */
587                         counts = 10;
588                         dummy = 0;
589                         callidlen = sizeof(callidstr);
590                         if (!OSPPTransactionRequestAuthorisation(result->handle, source, "", 
591                                   callerid,OSPC_E164, extension, OSPC_E164, NULL, 1, &callid, NULL, &counts, &dummy, NULL)) {
592                                 if (counts) {
593                                         tokenlen = sizeof(token);
594                                         result->numresults = counts - 1;
595                                         if (!OSPPTransactionGetFirstDestination(result->handle, 0, NULL, NULL, &timelimit, &callidlen, callidstr, 
596                                                 sizeof(callednum), callednum, sizeof(callingnum), callingnum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) {
597                                                 ast_log(LOG_DEBUG, "Got destination '%s' and called: '%s' calling: '%s' for '%s' (provider '%s')\n",
598                                                         destination, callednum, callingnum, extension, provider);
599                                                 ast_channel_setwhentohangup (chan, timelimit);  /* Only support OSP server with only one duration limit */
600                                                 do {
601                                                         if (!OSPPTransactionIsDestOSPEnabled (result->handle, &ospenabled) && (ospenabled == OSPE_OSP_FALSE)) {
602                                                                 result->token[0] = 0;
603                                                         }
604                                                         else {
605                                                                 ast_base64encode(result->token, token, tokenlen, sizeof(result->token) - 1);
606                                                         }
607                                                         if ((strlen(destination) > 2) && !OSPPTransactionGetDestProtocol(result->handle, &prot)) {
608                                                                 res = 1;
609                                                                 /* Strip leading and trailing brackets */
610                                                                 destination[strlen(destination) - 1] = '\0';
611                                                                 switch(prot) {
612                                                                 case OSPE_DEST_PROT_H323_SETUP:
613                                                                         ast_copy_string(result->tech, "H323", sizeof(result->tech));
614                                                                         snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
615                                                                         break;
616                                                                 case OSPE_DEST_PROT_SIP:
617                                                                         ast_copy_string(result->tech, "SIP", sizeof(result->tech));
618                                                                         snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
619                                                                         break;
620                                                                 case OSPE_DEST_PROT_IAX:
621                                                                         ast_copy_string(result->tech, "IAX", sizeof(result->tech));
622                                                                         snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
623                                                                         break;
624                                                                 default:
625                                                                         ast_log(LOG_DEBUG, "Unknown destination protocol '%d', skipping...\n", prot);
626                                                                         res = 0;
627                                                                 }
628                                                                 if (!res && result->numresults) {
629                                                                         result->numresults--;
630                                                                         if (OSPPTransactionGetNextDestination(result->handle, OSPC_FAIL_INCOMPATIBLE_DEST, 0, NULL, NULL, &timelimit, &callidlen, callidstr, 
631                                                                                         sizeof(callednum), callednum, sizeof(callingnum), callingnum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) {
632                                                                                         break;
633                                                                         }
634                                                                 }
635                                                         } else {
636                                                                 ast_log(LOG_DEBUG, "Missing destination protocol\n");
637                                                                 break;
638                                                         }
639                                                 } while(!res && result->numresults);
640                                         }
641                                 }
642                                 
643                         }
644                         OSPPCallIdDelete(&callid);
645                 }
646                 if (!res) {
647                         OSPPTransactionDelete(result->handle);
648                         result->handle = -1;
649                 }
650                 
651         }
652         if (!osp) 
653                 ast_log(LOG_NOTICE, "OSP Provider '%s' does not exist!\n", provider);
654         if (chan) {
655                 cres = ast_autoservice_stop(chan);
656                 if (cres < 0)
657                         return cres;
658         }
659         return res;
660 }
661
662 int ast_osp_next(struct ast_osp_result *result, int cause)
663 {
664         int res = 0;
665         int tokenlen;
666         unsigned int dummy=0;
667         unsigned int timelimit;
668         unsigned int callidlen;
669         char callidstr[OSPC_CALLID_MAXSIZE] = "";
670         char callednum[2048]="";
671         char callingnum[2048]="";
672         char destination[2048]="";
673         char token[2000];
674         OSPE_DEST_PROT prot;
675         OSPE_DEST_OSP_ENABLED ospenabled;
676
677         result->tech[0] = '\0';
678         result->dest[0] = '\0';
679         result->token[0] = '\0';
680
681         if (result->handle > -1) {
682                 dummy = 0;
683                 callidlen = sizeof(callidstr);
684                 if (result->numresults) {
685                         tokenlen = sizeof(token);
686                         while(!res && result->numresults) {
687                                 result->numresults--;
688                                 if (!OSPPTransactionGetNextDestination(result->handle, OSPC_FAIL_INCOMPATIBLE_DEST, 0, NULL, NULL, &timelimit, &callidlen, callidstr, 
689                                                                         sizeof(callednum), callednum, sizeof(callingnum), callingnum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) {
690                                         if (!OSPPTransactionIsDestOSPEnabled (result->handle, &ospenabled) && (ospenabled == OSPE_OSP_FALSE)) {
691                                                 result->token[0] = 0;
692                                         }
693                                         else {
694                                                 ast_base64encode(result->token, token, tokenlen, sizeof(result->token) - 1);
695                                         }
696                                         if ((strlen(destination) > 2) && !OSPPTransactionGetDestProtocol(result->handle, &prot)) {
697                                                 res = 1;
698                                                 /* Strip leading and trailing brackets */
699                                                 destination[strlen(destination) - 1] = '\0';
700                                                 switch(prot) {
701                                                 case OSPE_DEST_PROT_H323_SETUP:
702                                                         ast_copy_string(result->tech, "H323", sizeof(result->tech));
703                                                         snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
704                                                         break;
705                                                 case OSPE_DEST_PROT_SIP:
706                                                         ast_copy_string(result->tech, "SIP", sizeof(result->tech));
707                                                         snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
708                                                         break;
709                                                 case OSPE_DEST_PROT_IAX:
710                                                         ast_copy_string(result->tech, "IAX", sizeof(result->tech));
711                                                         snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
712                                                         break;
713                                                 default:
714                                                         ast_log(LOG_DEBUG, "Unknown destination protocol '%d', skipping...\n", prot);
715                                                         res = 0;
716                                                 }
717                                         } else {
718                                                 ast_log(LOG_DEBUG, "Missing destination protocol\n");
719                                                 break;
720                                         }
721                                 }
722                         }
723                         
724                 }
725                 if (!res) {
726                         OSPPTransactionDelete(result->handle);
727                         result->handle = -1;
728                 }
729                 
730         }
731         return res;
732 }
733
734 static enum OSPEFAILREASON cause2reason(int cause)
735 {
736         switch(cause) {
737         case AST_CAUSE_BUSY:
738                 return OSPC_FAIL_USER_BUSY;
739         case AST_CAUSE_CONGESTION:
740                 return OSPC_FAIL_SWITCHING_EQUIPMENT_CONGESTION;
741         case AST_CAUSE_UNALLOCATED:
742                 return OSPC_FAIL_UNALLOC_NUMBER;
743         case AST_CAUSE_NOTDEFINED:
744                 return OSPC_FAIL_NORMAL_UNSPECIFIED;
745         case AST_CAUSE_NOANSWER:
746                 return OSPC_FAIL_NO_ANSWER_FROM_USER;
747         case AST_CAUSE_NORMAL:
748         default:
749                 return OSPC_FAIL_NORMAL_CALL_CLEARING;
750         }
751 }
752
753 int ast_osp_terminate(int handle, int cause, time_t start, time_t duration)
754 {
755         unsigned int dummy = 0;
756         int res = -1;
757         enum OSPEFAILREASON reason;
758
759         time_t endTime = 0;
760         time_t alertTime = 0;
761         time_t connectTime = 0;
762         unsigned isPddInfoPresent = 0;
763         unsigned pdd = 0;
764         unsigned releaseSource = 0;
765         unsigned char *confId = "";
766         
767         reason = cause2reason(cause);
768         if (OSPPTransactionRecordFailure(handle, reason))
769                 ast_log(LOG_WARNING, "Failed to record call termination for handle %d\n", handle);
770         else if (OSPPTransactionReportUsage(handle, duration, start,
771                                endTime,alertTime,connectTime,isPddInfoPresent,pdd,releaseSource,confId,
772                                0, 0, 0, 0, &dummy, NULL))
773                 ast_log(LOG_WARNING, "Failed to report duration for handle %d\n", handle);
774         else {
775                 ast_log(LOG_DEBUG, "Completed recording handle %d\n", handle);
776                 OSPPTransactionDelete(handle);
777                 res = 0;
778         }
779         return res;
780 }
781
782 static int config_load(void)
783 {
784         struct ast_config *cfg;
785         char *cat;
786         struct osp_provider *osp, *prev = NULL, *next;
787         ast_mutex_lock(&osplock);
788         osp = providers;
789         while(osp) {
790                 osp->dead = 1;
791                 osp = osp->next;
792         }
793         ast_mutex_unlock(&osplock);
794         cfg = ast_config_load("osp.conf");
795         if (cfg) {
796                 if (!initialized) {
797                         cat = ast_variable_retrieve(cfg, "general", "accelerate");
798                         if (cat && ast_true(cat))
799                                 if (OSPPInit(1)) {
800                                         ast_log(LOG_WARNING, "Failed to enable hardware accelleration, falling back to software mode\n");
801                                         OSPPInit(0);
802                                 } else
803                                         hardware = 1;
804                         else
805                                 OSPPInit(0);
806                         initialized = 1;
807                 }
808                 cat = ast_variable_retrieve(cfg, "general", "tokenformat");
809                 if (cat) {
810                         if ((sscanf(cat, "%d", &tokenformat) != 1) || (tokenformat < TOKEN_ALGO_SIGNED) || (tokenformat > TOKEN_ALGO_BOTH)) {
811                                 tokenformat = TOKEN_ALGO_SIGNED;
812                                 ast_log(LOG_WARNING, "tokenformat should be an integer from 0 to 2, not '%s'\n", cat);
813                         }
814                 }
815                 cat = ast_category_browse(cfg, NULL);
816                 while(cat) {
817                         if (strcasecmp(cat, "general"))
818                                 osp_build(cfg, cat);
819                         cat = ast_category_browse(cfg, cat);
820                 }
821                 ast_config_destroy(cfg);
822         } else
823                 ast_log(LOG_NOTICE, "No OSP configuration found.  OSP support disabled\n");
824         ast_mutex_lock(&osplock);
825         osp = providers;
826         while(osp) {
827                 next = osp->next;
828                 if (osp->dead) {
829                         if (prev)
830                                 prev->next = next;
831                         else
832                                 providers = next;
833                         /* XXX Cleanup OSP structure first XXX */
834                         free(osp);
835                 } else 
836                         prev = osp;
837                 osp = next;
838         }
839         ast_mutex_unlock(&osplock);
840         return 0;
841 }
842
843 static char show_osp_usage[] = 
844 "Usage: show osp\n"
845 "       Displays information on Open Settlement Protocol\n";
846
847 static struct ast_cli_entry cli_show_osp = 
848 { { "show", "osp", NULL }, show_osp, "Displays OSP information", show_osp_usage };
849
850 int reload(void)
851 {
852         config_load();
853         ast_log(LOG_NOTICE, "XXX Should reload OSP config XXX\n");
854         return 0;
855 }
856
857 int load_module(void)
858 {
859         config_load();
860         ast_cli_register(&cli_show_osp);
861         return 0;
862 }
863
864 int unload_module(void)
865 {
866         /* Can't unload this once we're loaded */
867         return -1;
868 }
869
870 char *description(void)
871 {
872         return "Open Settlement Protocol Support";
873 }
874
875 int usecount(void)
876 {
877         /* We should never be unloaded */
878         return 1;
879 }
880
881 char *key()
882 {
883         return ASTERISK_GPL_KEY;
884 }