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