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