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