Merged revisions 29196 via svnmerge from
[asterisk/asterisk.git] / res / res_osp.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! 
20  * \file
21  * \brief Provide Open Settlement Protocol capability
22  *
23  * \author Mark Spencer <markster@digium.com>
24  *
25  * \arg See also: \ref app_osplookup.c
26  */
27
28 /*** MODULEINFO
29         <depend>libosptk</depend>
30         <depend>ssl</depend>
31  ***/
32
33 #include <sys/types.h>
34 #include <osp/osp.h>
35 #include <osp/osputils.h>
36 #include <openssl/err.h>
37 #include <stdio.h>
38 #include <dirent.h>
39 #include <string.h>
40 #include <errno.h>
41 #include <unistd.h>
42 #include <fcntl.h>
43 #include <openssl/bio.h>
44 #include <openssl/pem.h>
45 #include <openssl/evp.h>
46
47 #include "asterisk.h"
48
49 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
50
51 #include "asterisk/file.h"
52 #include "asterisk/channel.h"
53 #include "asterisk/logger.h"
54 #include "asterisk/say.h"
55 #include "asterisk/module.h"
56 #include "asterisk/options.h"
57 #include "asterisk/crypto.h"
58 #include "asterisk/md5.h"
59 #include "asterisk/cli.h"
60 #include "asterisk/io.h"
61 #include "asterisk/lock.h"
62 #include "asterisk/astosp.h"
63 #include "asterisk/config.h"
64 #include "asterisk/utils.h"
65 #include "asterisk/lock.h"
66 #include "asterisk/causes.h"
67 #include "asterisk/callerid.h"
68 #include "asterisk/pbx.h"
69
70 /* OSP Authentication Policy */
71 enum osp_authpolicy {
72         OSP_AUTH_NO,
73         OSP_AUTH_YES,
74         OSP_AUTH_EXCLUSIVE
75 };
76
77 #define OSP_CONFIG_FILE                 ((char*)"osp.conf")
78 #define OSP_GENERAL_CAT                 ((char*)"general")
79 #define OSP_MAX_CERTS                   ((unsigned int)10)
80 #define OSP_MAX_SRVS                    ((unsigned int)10)
81 #define OSP_DEF_MAXCONNECTIONS  ((unsigned int)20)
82 #define OSP_MIN_MAXCONNECTIONS  ((unsigned int)1)
83 #define OSP_MAX_MAXCONNECTIONS  ((unsigned int)1000)
84 #define OSP_DEF_RETRYDELAY              ((unsigned int)0)
85 #define OSP_MIN_RETRYDELAY              ((unsigned int)0)
86 #define OSP_MAX_RETRYDELAY              ((unsigned int)10)
87 #define OSP_DEF_RETRYLIMIT              ((unsigned int)2)
88 #define OSP_MIN_RETRYLIMIT              ((unsigned int)0)
89 #define OSP_MAX_RETRYLIMIT              ((unsigned int)100)
90 #define OSP_DEF_TIMEOUT                 ((unsigned int)500)
91 #define OSP_MIN_TIMEOUT                 ((unsigned int)200)
92 #define OSP_MAX_TIMEOUT                 ((unsigned int)10000)
93 #define OSP_DEF_AUTHPOLICY              ((enum osp_authpolicy)OSP_AUTH_YES)
94 #define OSP_AUDIT_URL                   ((char*)"localhost")
95 #define OSP_LOCAL_VALIDATION    ((int)1)
96 #define OSP_SSL_LIFETIME                ((unsigned int)300)
97 #define OSP_HTTP_PERSISTENCE    ((int)1)
98 #define OSP_CUSTOMER_ID                 ((char*)"")
99 #define OSP_DEVICE_ID                   ((char*)"")
100 #define OSP_DEF_DESTINATIONS    ((unsigned int)5)
101
102 struct osp_provider {
103         char name[OSP_NORSTR_SIZE];
104         char privatekey[OSP_NORSTR_SIZE];
105         char localcert[OSP_NORSTR_SIZE];
106         unsigned int cacount;
107         char cacerts[OSP_MAX_CERTS][OSP_NORSTR_SIZE]; 
108         unsigned int spcount;
109         char srvpoints[OSP_MAX_SRVS][OSP_NORSTR_SIZE];
110         int maxconnections;
111         int retrydelay;
112         int retrylimit;
113         int timeout;
114         char source[OSP_NORSTR_SIZE];
115         enum osp_authpolicy authpolicy;
116         OSPTPROVHANDLE handle;
117         struct osp_provider *next;
118 };
119
120 AST_MUTEX_DEFINE_STATIC(osplock);
121 static unsigned int osp_usecount = 0;
122 static int osp_initialized = 0;
123 static int osp_hardware = 0;
124 static struct osp_provider* ospproviders = NULL;
125 static unsigned int osp_tokenformat = TOKEN_ALGO_SIGNED;
126
127 static int osp_buildProvider(
128         struct ast_config* cfg,         /* OSP configuration */
129         char* provider);                        /* OSP provider context name */
130 static int osp_getPolicy(
131         const char* provider,           /* OSP provider context name */
132         int* policy);                           /* OSP authentication policy, output */
133 static int osp_genTransaction(
134         const char* provider,           /* OSP provider context name */
135         int* transaction,                       /* OSP transaction handle, output */
136         unsigned int sourcesize,        /* Size of source buffer, in/output */
137         char* source);                          /* Source of provider context, output */
138 static int osp_valToken(
139         int transaction,                        /* OSP transaction handle */
140         const char* source,                     /* Source of in_bound call */
141         const char* dest,                       /* Destination of in_bound call */
142         const char* calling,            /* Calling number */
143         const char* called,                     /* Called number */
144         const char* token,                      /* OSP token, may be empty */
145         unsigned int* timelimit);       /* Call duration limit, output */
146 static unsigned int osp_choTimelimit(
147         unsigned int in,                        /* In_bound OSP timelimit */
148         unsigned int out);                      /* Out_bound OSP timelimit */
149 static enum OSPEFAILREASON reason2cause(
150         int reason);                            /* Last call failure reason */
151 static int osp_chkDest(
152         const char* callednum,                  /* Called number */
153         const char* callingnum,                 /* Calling number */
154         char* destination,                              /* Destination IP in OSP format */
155         unsigned int tokenlen,                  /* OSP token length */
156         const char* token,                              /* OSP token */
157         enum OSPEFAILREASON* cause,             /* Failure cause, output */
158         struct ast_osp_result* result); /* OSP lookup results, in/output */
159
160 static int osp_load(void);
161 static int osp_unload(void);
162 static int osp_show(int fd, int argc, char *argv[]);
163
164 static int osp_buildProvider(
165         struct ast_config *cfg,         /* OSP configuration */
166         char* provider)                         /* OSP provider context name */
167 {
168         int res;
169         unsigned int t, i, j;
170         struct osp_provider* p;
171         struct ast_variable* v;
172         OSPTPRIVATEKEY privatekey;
173         OSPTCERT localcert;
174         const char* psrvpoints[OSP_MAX_SRVS];
175         OSPTCERT cacerts[OSP_MAX_CERTS];
176         const OSPTCERT* pcacerts[OSP_MAX_CERTS];
177         int error = OSPC_ERR_NO_ERROR;
178
179         p = ast_calloc(1, sizeof(*p));
180         if (!p) {
181                 ast_log(LOG_ERROR, "Out of memory\n");
182                 return(-1);
183         }
184
185         ast_copy_string(p->name, provider, sizeof(p->name));
186         p->handle = OSP_INVALID_HANDLE;
187         snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s-privatekey.pem", ast_config_AST_KEY_DIR, provider);
188         snprintf(p->localcert, sizeof(p->localcert), "%s/%s-localcert.pem", ast_config_AST_KEY_DIR, provider);
189         p->maxconnections = OSP_DEF_MAXCONNECTIONS;
190         p->retrydelay = OSP_DEF_RETRYDELAY;
191         p->retrylimit = OSP_DEF_RETRYLIMIT;
192         p->timeout = OSP_DEF_TIMEOUT;
193         p->authpolicy = OSP_DEF_AUTHPOLICY;
194
195         v = ast_variable_browse(cfg, provider);
196         while(v) {
197                 if (!strcasecmp(v->name, "privatekey")) {
198                         if (v->value[0] == '/') {
199                                 ast_copy_string(p->privatekey, v->value, sizeof(p->privatekey));
200                         } else {
201                                 snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s", ast_config_AST_KEY_DIR, v->value);
202                         }
203                         ast_log(LOG_DEBUG, "OSP: privatekey '%s'\n", p->privatekey);
204                 } else if (!strcasecmp(v->name, "localcert")) {
205                         if (v->value[0] == '/') {
206                                 ast_copy_string(p->localcert, v->value, sizeof(p->localcert));
207                         } else {
208                                 snprintf(p->localcert, sizeof(p->localcert), "%s/%s", ast_config_AST_KEY_DIR, v->value);
209                         }
210                         ast_log(LOG_DEBUG, "OSP: localcert '%s'\n", p->localcert);
211                 } else if (!strcasecmp(v->name, "cacert")) {
212                         if (p->cacount < OSP_MAX_CERTS) {
213                                 if (v->value[0] == '/') {
214                                         ast_copy_string(p->cacerts[p->cacount], v->value, sizeof(p->cacerts[0]));
215                                 } else {
216                                         snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s", ast_config_AST_KEY_DIR, v->value);
217                                 }
218                                 ast_log(LOG_DEBUG, "OSP: cacert[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]);
219                                 p->cacount++;
220                         } else {
221                                 ast_log(LOG_WARNING, "OSP: Too many CA Certificates at line %d\n", v->lineno);
222                         }
223                 } else if (!strcasecmp(v->name, "servicepoint")) {
224                         if (p->spcount < OSP_MAX_SRVS) {
225                                 ast_copy_string(p->srvpoints[p->spcount], v->value, sizeof(p->srvpoints[0]));
226                                 ast_log(LOG_DEBUG, "OSP: servicepoint[%d]: '%s'\n", p->spcount, p->srvpoints[p->spcount]);
227                                 p->spcount++;
228                         } else {
229                                 ast_log(LOG_WARNING, "OSP: Too many Service Points at line %d\n", v->lineno);
230                         }
231                 } else if (!strcasecmp(v->name, "maxconnections")) {
232                         if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_MAXCONNECTIONS) && (t <= OSP_MAX_MAXCONNECTIONS)) {
233                                 p->maxconnections = t;
234                                 ast_log(LOG_DEBUG, "OSP: maxconnections '%d'\n", t);
235                         } else {
236                                 ast_log(LOG_WARNING, "OSP: maxconnections should be an integer from %d to %d, not '%s' at line %d\n", 
237                                         OSP_MIN_MAXCONNECTIONS, OSP_MAX_MAXCONNECTIONS, v->value, v->lineno);
238                         }
239                 } else if (!strcasecmp(v->name, "retrydelay")) {
240                         if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_RETRYDELAY) && (t <= OSP_MAX_RETRYDELAY)) {
241                                 p->retrydelay = t;
242                                 ast_log(LOG_DEBUG, "OSP: retrydelay '%d'\n", t);
243                         } else {
244                                 ast_log(LOG_WARNING, "OSP: retrydelay should be an integer from %d to %d, not '%s' at line %d\n", 
245                                         OSP_MIN_RETRYDELAY, OSP_MAX_RETRYDELAY, v->value, v->lineno);
246                         }
247                 } else if (!strcasecmp(v->name, "retrylimit")) {
248                         if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_RETRYLIMIT) && (t <= OSP_MAX_RETRYLIMIT)) {
249                                 p->retrylimit = t;
250                                 ast_log(LOG_DEBUG, "OSP: retrylimit '%d'\n", t);
251                         } else {
252                                 ast_log(LOG_WARNING, "OSP: retrylimit should be an integer from %d to %d, not '%s' at line %d\n", 
253                                         OSP_MIN_RETRYLIMIT, OSP_MAX_RETRYLIMIT, v->value, v->lineno);
254                         }
255                 } else if (!strcasecmp(v->name, "timeout")) {
256                         if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_TIMEOUT) && (t <= OSP_MAX_TIMEOUT)) {
257                                 p->timeout = t;
258                                 ast_log(LOG_DEBUG, "OSP: timeout '%d'\n", t);
259                         } else {
260                                 ast_log(LOG_WARNING, "OSP: timeout should be an integer from %d to %d, not '%s' at line %d\n", 
261                                         OSP_MIN_TIMEOUT, OSP_MAX_TIMEOUT, v->value, v->lineno);
262                         }
263                 } else if (!strcasecmp(v->name, "source")) {
264                         ast_copy_string(p->source, v->value, sizeof(p->source));
265                         ast_log(LOG_DEBUG, "OSP: source '%s'\n", p->source);
266                 } else if (!strcasecmp(v->name, "authpolicy")) {
267                         if ((sscanf(v->value, "%d", &t) == 1) && ((t == OSP_AUTH_NO) || (t == OSP_AUTH_YES) || (t == OSP_AUTH_EXCLUSIVE))) {
268                                 p->authpolicy = t;
269                                 ast_log(LOG_DEBUG, "OSP: authpolicy '%d'\n", t);
270                         } else {
271                                 ast_log(LOG_WARNING, "OSP: authpolicy should be %d, %d or %d, not '%s' at line %d\n", 
272                                         OSP_AUTH_NO, OSP_AUTH_YES, OSP_AUTH_EXCLUSIVE, v->value, v->lineno);
273                         }
274                 }
275                 v = v->next;
276         }
277
278         error = OSPPUtilLoadPEMPrivateKey(p->privatekey, &privatekey);
279         if (error != OSPC_ERR_NO_ERROR) {
280                 ast_log(LOG_WARNING, "OSP: Unable to load privatekey '%s'\n", p->privatekey);
281                 free(p);
282                 return(-1);
283         }
284
285         error = OSPPUtilLoadPEMCert(p->localcert, &localcert);
286         if (error != OSPC_ERR_NO_ERROR) {
287                 ast_log(LOG_WARNING, "OSP: Unable to load localcert '%s'\n", p->localcert);
288                 if (privatekey.PrivateKeyData) {
289                         free(privatekey.PrivateKeyData);
290                 }
291                 free(p);
292                 return(-1);
293         }
294
295         if (p->cacount < 1) {
296                 snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s-cacert.pem", ast_config_AST_KEY_DIR, provider);
297                 ast_log(LOG_DEBUG, "OSP: cacert[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]);
298                 p->cacount++;
299         }
300         for (i = 0; i < p->cacount; i++) {
301                 error = OSPPUtilLoadPEMCert(p->cacerts[i], &cacerts[i]);
302                 if (error != OSPC_ERR_NO_ERROR) {
303                         ast_log(LOG_WARNING, "OSP: Unable to load cacert '%s'\n", p->cacerts[i]);
304                         for (j = 0; j < i; j++) {
305                                 if (cacerts[j].CertData) {
306                                         free(cacerts[j].CertData);
307                                 }
308                         }
309                         if (localcert.CertData) {
310                                 free(localcert.CertData);
311                         }
312                         if (privatekey.PrivateKeyData) {
313                                 free(privatekey.PrivateKeyData);
314                         }
315                         free(p);
316                         return(-1);
317                 }
318                 pcacerts[i] = &cacerts[i];
319         }
320         
321         for (i = 0; i < p->spcount; i++) {
322                 psrvpoints[i] = p->srvpoints[i];
323         }
324
325         error = OSPPProviderNew(
326                 p->spcount, psrvpoints,
327                 NULL,
328                 OSP_AUDIT_URL,
329                 &privatekey,
330                 &localcert,
331                 p->cacount, pcacerts,
332                 OSP_LOCAL_VALIDATION,
333                 OSP_SSL_LIFETIME,
334                 p->maxconnections,
335                 OSP_HTTP_PERSISTENCE,
336                 p->retrydelay,
337                 p->retrylimit,
338                 p->timeout,
339                 OSP_CUSTOMER_ID,
340                 OSP_DEVICE_ID,
341                 &p->handle);
342         if (error != OSPC_ERR_NO_ERROR) {
343                 ast_log(LOG_WARNING, "OSP: Unable to initialize provider '%s'\n", provider);
344                 free(p);
345                 res = -1;
346         } else {
347                 ast_log(LOG_DEBUG, "OSP: provider '%s'\n", provider);
348                 ast_mutex_lock(&osplock);
349                 p->next = ospproviders;
350                 ospproviders = p;
351                 ast_mutex_unlock(&osplock);     
352                 res = 0;
353         }
354
355         for (i = 0; i < p->cacount; i++) {
356                 if (cacerts[i].CertData) {
357                         free(cacerts[i].CertData);
358                 }
359         }
360         if (localcert.CertData) {
361                 free(localcert.CertData);
362         }
363         if (privatekey.PrivateKeyData) {
364                 free(privatekey.PrivateKeyData);
365         }
366
367         return(res);
368 }
369
370 static int osp_getPolicy(
371         const char* provider,           /* OSP provider context name */
372         int* policy)                            /* OSP authentication policy, output */
373 {
374         int res = 0;
375         struct osp_provider* p;
376
377         ast_mutex_lock(&osplock);
378         p = ospproviders;
379         while(p) {
380                 if (!strcasecmp(p->name, provider)) {
381                         *policy = p->authpolicy;
382                         ast_log(LOG_DEBUG, "OSP: authpolicy '%d'\n", *policy);
383                         res = 1;
384                         break;
385                 }
386                 p = p->next;
387         }
388         ast_mutex_unlock(&osplock);
389
390         return(res);
391 }
392
393 static int osp_genTransaction(
394         const char* provider,           /* OSP provider context name */
395         int* transaction,                       /* OSP transaction handle, output */
396         unsigned int sourcesize,        /* Size of source buffer, in/output */
397         char* source)                           /* Source of provider context, output */
398 {
399         int res = 0;
400         struct osp_provider *p;
401         int error;
402
403         ast_mutex_lock(&osplock);
404         p = ospproviders;
405         while(p) {
406                 if (!strcasecmp(p->name, provider)) {
407                         error = OSPPTransactionNew(p->handle, transaction);
408                         if (error == OSPC_ERR_NO_ERROR) {
409                                 ast_log(LOG_DEBUG, "OSP: transaction '%d'\n", *transaction);
410                                 ast_copy_string(source, p->source, sourcesize);
411                                 ast_log(LOG_DEBUG, "OSP: source '%s'\n", source);
412                                 res = 1;
413                         } else {
414                                 *transaction = OSP_INVALID_HANDLE;
415                                 ast_log(LOG_WARNING, "OSP: Unable to create transaction handle\n");
416                                 res = -1;
417                         }
418                         break;
419                 }
420                 p = p->next;
421         }
422         ast_mutex_unlock(&osplock);
423
424         return(res);
425 }
426
427 static int osp_valToken(
428         int transaction,                        /* OSP transaction handle */
429         const char* source,                     /* Source of in_bound call */
430         const char* dest,                       /* Destination of in_bound call */
431         const char* calling,            /* Calling number */
432         const char* called,                     /* Called number */
433         const char* token,                      /* OSP token, may be empty */
434         unsigned int* timelimit)        /* Call duration limit, output */
435 {
436         int res = 0;
437         char tokenstr[OSP_TOKSTR_SIZE];
438         int tokenlen;
439         unsigned int authorised;
440         unsigned int dummy = 0;
441         int error;
442
443         tokenlen = ast_base64decode(tokenstr, token, strlen(token));
444         error = OSPPTransactionValidateAuthorisation(
445                 transaction, 
446                 source, dest, NULL, NULL,
447                 calling ? calling : "", OSPC_E164, 
448                 called, OSPC_E164, 
449                 0, NULL,
450                 tokenlen, tokenstr, 
451                 &authorised, 
452                 timelimit, 
453                 &dummy, NULL, 
454                 osp_tokenformat); 
455         if (error == OSPC_ERR_NO_ERROR) {
456                 if (authorised) {
457                         ast_log(LOG_DEBUG, "OSP: Authorised\n");
458                         res = 1;
459                 }
460         }
461         return(res);
462 }
463
464 int ast_osp_auth(
465         const char* provider,           /* OSP provider context name */
466         int* transaction,                       /* OSP transaction handle, output */
467         const char* source,                     /* Source of in_bound call */
468         const char* calling,            /* Calling number */
469         const char* called,                     /* Called number */
470         const char* token,                      /* OSP token, may be empty */
471         unsigned int* timelimit)        /* Call duration limit, output */
472 {
473         int res;
474         char dest[OSP_NORSTR_SIZE];
475         int policy = OSP_AUTH_YES;
476
477         *transaction = OSP_INVALID_HANDLE;
478         *timelimit = OSP_DEF_TIMELIMIT;
479
480         res = osp_getPolicy(provider, &policy);
481         if (!res) {
482                 ast_log(LOG_WARNING, "OSP: Unabe to find authentication policy\n");
483                 return(-1);
484         }
485
486         switch (policy) {
487                 case OSP_AUTH_NO:
488                         res = 1;
489                         break;
490                 case OSP_AUTH_EXCLUSIVE:
491                         if (ast_strlen_zero(token)) {
492                                 res = 0;
493                         } else if ((res = osp_genTransaction(provider, transaction, sizeof(dest), dest)) <= 0) {
494                                 *transaction = OSP_INVALID_HANDLE;
495                                 ast_log(LOG_WARNING, "OSP: Unable to generate transaction handle\n");
496                                 res = -1;
497                         } else {
498                                 res = osp_valToken(*transaction, source, dest, calling, called, token, timelimit);
499                         }
500                         break;
501                 case OSP_AUTH_YES:
502                 default:
503                         if (ast_strlen_zero(token)) {
504                                 res = 1;
505                         } else if ((res = osp_genTransaction(provider, transaction, sizeof(dest), dest)) <= 0) {
506                                 *transaction = OSP_INVALID_HANDLE;
507                                 ast_log(LOG_WARNING, "OSP: Unable to generate transaction handle\n");
508                                 res = -1;
509                         } else {
510                                 res = osp_valToken(*transaction, source, dest, calling, called, token, timelimit);
511                         }
512                         break;
513         }
514
515         if (!res) {
516                 OSPPTransactionRecordFailure(*transaction, OSPC_FAIL_CALL_REJECTED);
517         }
518
519         return(res);    
520 }
521
522 static unsigned int osp_choTimelimit(
523         unsigned int in,                        /* In_bound OSP timelimit */
524         unsigned int out)                       /* Out_bound OSP timelimit */
525 {
526         if (in == OSP_DEF_TIMELIMIT) {
527                 return (out);
528         } else if (out == OSP_DEF_TIMELIMIT) {
529                 return (in);
530         } else {
531                 return(in < out ? in : out);
532         }
533 }
534
535 static int osp_chkDest(
536         const char* callednum,                  /* Called number */
537         const char* callingnum,                 /* Calling number */
538         char* destination,                              /* Destination IP in OSP format */
539         unsigned int tokenlen,                  /* OSP token length */
540         const char* token,                              /* OSP token */
541         enum OSPEFAILREASON* cause,             /* Failure cause, output */
542         struct ast_osp_result* result)  /* OSP lookup results, in/output */
543 {
544         int res = 0;
545         OSPE_DEST_OSP_ENABLED enabled;
546         OSPE_DEST_PROT protocol;
547         int error;
548
549         if (strlen(destination) <= 2) {
550                 *cause = OSPC_FAIL_INCOMPATIBLE_DEST;
551         } else {
552                 error = OSPPTransactionIsDestOSPEnabled(result->outhandle, &enabled);
553                 if ((error == OSPC_ERR_NO_ERROR) && (enabled == OSPE_OSP_FALSE)) {
554                         result->token[0] = '\0';
555                 } else {
556                         ast_base64encode(result->token, token, tokenlen, sizeof(result->token) - 1);
557                 }
558
559                 error = OSPPTransactionGetDestProtocol(result->outhandle, &protocol);
560                 if (error != OSPC_ERR_NO_ERROR) {
561                         *cause = OSPC_FAIL_PROTOCOL_ERROR; 
562                 } else {
563                         res = 1;
564                         /* Strip leading and trailing brackets */
565                         destination[strlen(destination) - 1] = '\0';
566                         switch(protocol) {
567                                 case OSPE_DEST_PROT_H323_SETUP:
568                                         ast_copy_string(result->tech, "H323", sizeof(result->tech));
569                                         ast_log(LOG_DEBUG, "OSP: protocol '%d'\n", protocol);
570                                         snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
571                                         ast_copy_string(result->calling, callingnum, sizeof(result->calling));
572                                         break;
573                                 case OSPE_DEST_PROT_SIP:
574                                         ast_copy_string(result->tech, "SIP", sizeof(result->tech));
575                                         ast_log(LOG_DEBUG, "OSP: protocol '%d'\n", protocol);
576                                         snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
577                                         ast_copy_string(result->calling, callingnum, sizeof(result->calling));
578                                         break;
579                                 case OSPE_DEST_PROT_IAX:
580                                         ast_copy_string(result->tech, "IAX", sizeof(result->tech));
581                                         ast_log(LOG_DEBUG, "OSP: protocol '%d'\n", protocol);
582                                         snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1);
583                                         ast_copy_string(result->calling, callingnum, sizeof(result->calling));
584                                         break;
585                                 default:
586                                         ast_log(LOG_DEBUG, "OSP: Unknown protocol '%d'\n", protocol);
587                                         *cause = OSPC_FAIL_PROTOCOL_ERROR; 
588                                         res = 0;
589                         }
590                 }
591         }
592         return(res);
593 }
594
595 int ast_osp_lookup(
596         const char* provider,                   /* OSP provider conttext name */
597         const char* srcdev,                             /* Source device of out_bound call */
598         const char* calling,                    /* Calling number */
599         const char* called,                             /* Called number */
600         struct ast_osp_result* result)  /* OSP lookup results, in/output */
601 {
602         int res;
603         char source[OSP_NORSTR_SIZE];
604         unsigned int callidlen;
605         char callidstr[OSPC_CALLID_MAXSIZE];
606         char callingnum[OSP_NORSTR_SIZE];
607         char callednum[OSP_NORSTR_SIZE];
608         char destination[OSP_NORSTR_SIZE];
609         unsigned int tokenlen;
610         char token[OSP_TOKSTR_SIZE];
611         unsigned int dummy = 0;
612         enum OSPEFAILREASON cause;
613         int error;
614
615         result->outhandle = OSP_INVALID_HANDLE;
616         result->tech[0] = '\0';
617         result->dest[0] = '\0';
618         result->calling[0] = '\0';
619         result->token[0] = '\0';
620         result->numresults = 0;
621         result->outtimelimit = OSP_DEF_TIMELIMIT;
622
623         if ((res = osp_genTransaction(provider, &result->outhandle, sizeof(source), source)) <= 0) {
624                 result->outhandle = OSP_INVALID_HANDLE;
625                 if (result->inhandle != OSP_INVALID_HANDLE) {
626                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
627                 }
628                 ast_log(LOG_WARNING, "OSP: Unable to generate transaction handle\n");
629                 return(-1);
630         }
631
632         res = 0;
633         dummy = 0;
634         result->numresults = OSP_DEF_DESTINATIONS;
635         error = OSPPTransactionRequestAuthorisation(
636                 result->outhandle, 
637                 source, srcdev,
638                 calling ? calling : "", OSPC_E164, 
639                 called, OSPC_E164, 
640                 NULL, 
641                 0, NULL, 
642                 NULL, 
643                 &result->numresults, 
644                 &dummy, NULL);
645         if (error != OSPC_ERR_NO_ERROR) {
646                 result->numresults = 0;
647                 OSPPTransactionRecordFailure(result->outhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
648                 if (result->inhandle != OSP_INVALID_HANDLE) {
649                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
650                 }
651                 return(res);
652         }
653
654         if (!result->numresults) {
655                 result->numresults = 0;
656                 OSPPTransactionRecordFailure(result->outhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
657                 if (result->inhandle != OSP_INVALID_HANDLE) {
658                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
659                 }
660                 return(res);
661         }
662
663         callidlen = sizeof(callidstr);
664         tokenlen = sizeof(token);
665         error = OSPPTransactionGetFirstDestination(
666                 result->outhandle, 
667                 0, NULL, NULL, 
668                 &result->outtimelimit, 
669                 &callidlen, callidstr,
670                 sizeof(callednum), callednum, 
671                 sizeof(callingnum), callingnum, 
672                 sizeof(destination), destination, 
673                 0, NULL, 
674                 &tokenlen, token);
675         if (error != OSPC_ERR_NO_ERROR) {
676                 result->token[0] = '\0';
677                 result->numresults = 0;
678                 result->outtimelimit = OSP_DEF_TIMELIMIT;
679                 OSPPTransactionRecordFailure(result->outhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
680                 if (result->inhandle != OSP_INVALID_HANDLE) {
681                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
682                 }
683                 ast_log(LOG_DEBUG, "OSP: Unable to get first route\n");
684                 return(res);
685         }
686
687         do {
688                 result->outtimelimit = osp_choTimelimit(result->intimelimit, result->outtimelimit);
689                 ast_log(LOG_DEBUG, "OSP: outtimelimit '%d'\n", result->outtimelimit);
690                 ast_log(LOG_DEBUG, "OSP: called '%s'\n", callednum);
691                 ast_log(LOG_DEBUG, "OSP: calling '%s'\n", callingnum);
692                 ast_log(LOG_DEBUG, "OSP: destination '%s'\n", destination);
693                 ast_log(LOG_DEBUG, "OSP: token size '%d'\n", tokenlen);
694
695                 res = osp_chkDest(callednum, callingnum, destination, tokenlen, token, &cause, result);
696                 if (!res) {
697                         result->numresults--;
698                         if (result->numresults) {
699                                 callidlen = sizeof(callidstr);
700                                 tokenlen = sizeof(token);
701                                 error = OSPPTransactionGetNextDestination(
702                                         result->outhandle, 
703                                         cause, 
704                                         0, NULL, NULL, 
705                                         &result->outtimelimit, 
706                                         &callidlen, callidstr,
707                                         sizeof(callednum), callednum, 
708                                         sizeof(callingnum), callingnum, 
709                                         sizeof(destination), destination, 
710                                         0, NULL, 
711                                         &tokenlen, token);
712                                 if (error != OSPC_ERR_NO_ERROR) {
713                                         result->token[0] = '\0';
714                                         result->numresults = 0;
715                                         result->outtimelimit = OSP_DEF_TIMELIMIT;
716                                         OSPPTransactionRecordFailure(result->outhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
717                                         if (result->inhandle != OSP_INVALID_HANDLE) {
718                                                 OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
719                                         }
720                                         break;
721                                 }
722                         } else {
723                                 result->token[0] = '\0';
724                                 result->numresults = 0;
725                                 result->outtimelimit = OSP_DEF_TIMELIMIT;
726                                 OSPPTransactionRecordFailure(result->outhandle, cause);
727                                 if (result->inhandle != OSP_INVALID_HANDLE) {
728                                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
729                                 }
730                         }
731                 } else {
732                         result->numresults--;
733                 }
734         } while(!res && result->numresults);
735
736         return(res);
737 }
738
739 static enum OSPEFAILREASON reason2cause(
740         int reason)                                             /* Last call failure reason */
741 {
742         enum OSPEFAILREASON cause;
743
744         switch(reason) {
745                 case AST_CAUSE_NOTDEFINED:
746                         cause = OSPC_FAIL_NONE;
747                         break;
748                 case AST_CAUSE_BUSY:
749                         cause = OSPC_FAIL_USER_BUSY;
750                         break;
751                 case AST_CAUSE_CONGESTION:
752                         cause = OSPC_FAIL_SWITCHING_EQUIPMENT_CONGESTION;
753                         break;
754                 case AST_CAUSE_UNALLOCATED:
755                         cause = OSPC_FAIL_UNALLOC_NUMBER;
756                         break;
757                 case AST_CAUSE_NOANSWER:
758                         cause = OSPC_FAIL_NO_ANSWER_FROM_USER;
759                         break;
760                 case AST_CAUSE_NORMAL:
761                 default:
762                         cause = OSPC_FAIL_NORMAL_CALL_CLEARING;
763                         break;
764         }
765
766         return(cause);
767 }
768
769 int ast_osp_next(
770         int reason,                                             /* Last desintaion failure reason */
771         struct ast_osp_result *result)  /* OSP lookup results, output */
772 {
773         int res = 0;
774         unsigned int callidlen;
775         char callidstr[OSPC_CALLID_MAXSIZE];
776         char callingnum[OSP_NORSTR_SIZE];
777         char callednum[OSP_NORSTR_SIZE];
778         char destination[OSP_NORSTR_SIZE];
779         unsigned int tokenlen;
780         char token[OSP_TOKSTR_SIZE];
781         enum OSPEFAILREASON cause;
782         int error;
783
784         result->tech[0] = '\0';
785         result->dest[0] = '\0';
786         result->calling[0] = '\0';
787         result->token[0] = '\0';
788         result->outtimelimit = OSP_DEF_TIMELIMIT;
789
790         if (result->outhandle == OSP_INVALID_HANDLE) {
791                 result->numresults = 0;
792                 if (result->inhandle != OSP_INVALID_HANDLE) {
793                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
794                 }
795                 ast_log(LOG_WARNING, "OSP: Transaction handle undefined\n");
796                 return(-1);
797         }
798
799         cause = reason2cause(reason);
800         if (!result->numresults) {
801                 OSPPTransactionRecordFailure(result->outhandle, cause);
802                 if (result->inhandle != OSP_INVALID_HANDLE) {
803                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
804                 }
805                 ast_log(LOG_DEBUG, "OSP: No more destination\n");
806                 return(res);
807         }
808
809         while(!res && result->numresults) {
810                 result->numresults--;
811                 callidlen = sizeof(callidstr);
812                 tokenlen = sizeof(token);
813                 error = OSPPTransactionGetNextDestination(
814                         result->outhandle, 
815                         cause, 
816                         0, NULL, NULL, 
817                         &result->outtimelimit, 
818                         &callidlen, callidstr,
819                         sizeof(callednum), callednum, 
820                         sizeof(callingnum), callingnum, 
821                         sizeof(destination), destination, 
822                         0, NULL, 
823                         &tokenlen, token);
824                 if (error == OSPC_ERR_NO_ERROR) {
825                         result->outtimelimit = osp_choTimelimit(result->intimelimit, result->outtimelimit);
826                         ast_log(LOG_DEBUG, "OSP: outtimelimit '%d'\n", result->outtimelimit);
827                         ast_log(LOG_DEBUG, "OSP: called '%s'\n", callednum);
828                         ast_log(LOG_DEBUG, "OSP: calling '%s'\n", callingnum);
829                         ast_log(LOG_DEBUG, "OSP: destination '%s'\n", destination);
830                         ast_log(LOG_DEBUG, "OSP: token size '%d'\n", tokenlen);
831
832                         res = osp_chkDest(callednum, callingnum, destination, tokenlen, token, &cause, result);
833                         if (!res && !result->numresults) {
834                                 OSPPTransactionRecordFailure(result->outhandle, cause);
835                                 if (result->inhandle != OSP_INVALID_HANDLE) {
836                                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
837                                 }
838                         }
839                 } else {
840                         result->token[0] = '\0';
841                         result->numresults = 0;
842                         result->outtimelimit = OSP_DEF_TIMELIMIT;
843                         OSPPTransactionRecordFailure(result->outhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
844                         if (result->inhandle != OSP_INVALID_HANDLE) {
845                                 OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
846                         }
847                 }
848         }
849
850         return(res);
851 }
852
853 int ast_osp_finish(
854         int handle,                                             /* OSP in/out_bound transaction handle */
855         int reason,                                             /* Last destination failure reason */
856         time_t start,                                   /* Call start time */
857         time_t connect,                                 /* Call connect time */
858         time_t end)                                             /* Call end time*/
859 {
860         int res = 1;
861         unsigned int dummy = 0;
862         enum OSPEFAILREASON cause;
863         time_t alert = 0;
864         unsigned isPddInfoPresent = 0;
865         unsigned pdd = 0;
866         unsigned releaseSource = 0;
867         unsigned char *confId = "";
868         int error;
869         
870         if (handle == OSP_INVALID_HANDLE) {
871                 return(res);
872         }
873
874         if ((cause = reason2cause(reason)) != OSPC_FAIL_NONE) {
875                 OSPPTransactionRecordFailure(handle, cause);
876         }
877         error = OSPPTransactionReportUsage(
878                 handle, 
879                 difftime(end, connect), start, end, alert, connect, 
880                 isPddInfoPresent, pdd, 
881                 releaseSource, 
882                 confId,
883                 0, 0, 0, 0,
884                 &dummy, NULL);
885         if (error == OSPC_ERR_NO_ERROR) {
886                 ast_log(LOG_DEBUG, "OSP: Usage reported\n");
887                 res = 1;
888         } else {
889                 ast_log(LOG_DEBUG, "OSP: Unable to report usage, error = %d\n", error);
890                 res = 0;
891         }
892         OSPPTransactionDelete(handle);
893
894         return(res);
895 }
896
897 void ast_osp_adduse(void)
898 {
899         osp_usecount++;
900 }
901
902 void ast_osp_deluse(void)
903 {
904         if (osp_usecount > 0) {
905                 osp_usecount--;
906         }
907 }
908
909 static char osp_usage[] =
910 "Usage: show osp\n"
911 "       Displays information on Open Settlement Protocol support\n";
912
913 static struct ast_cli_entry osp_cli = {
914         {"show", "osp", NULL}, 
915         osp_show, 
916         "Displays OSP information", 
917         osp_usage 
918 };
919
920 static int osp_load(void)
921 {
922         char* t;
923         unsigned int v;
924         struct ast_config* cfg;
925         int error = OSPC_ERR_NO_ERROR;
926
927         cfg = ast_config_load(OSP_CONFIG_FILE);
928         if (cfg) {
929                 t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "accelerate");
930                 if (t && ast_true(t)) {
931                         if ((error = OSPPInit(1)) != OSPC_ERR_NO_ERROR) {
932                                 ast_log(LOG_WARNING, "OSP: Unable to enable hardware accelleration\n");
933                                 OSPPInit(0);
934                         } else {
935                                 osp_hardware = 1;
936                         }
937                 } else {
938                         OSPPInit(0);
939                 }
940                 ast_log(LOG_DEBUG, "OSP: osp_hardware '%d'\n", osp_hardware);
941
942                 t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "tokenformat");
943                 if (t) {
944                         if ((sscanf(t, "%d", &v) == 1) && 
945                                 ((v == TOKEN_ALGO_SIGNED) || (v == TOKEN_ALGO_UNSIGNED) || (v == TOKEN_ALGO_BOTH))) 
946                         {
947                                 osp_tokenformat = v;
948                         } else {
949                                 ast_log(LOG_WARNING, "tokenformat should be an integer from %d, %d or %d, not '%s'\n", 
950                                         TOKEN_ALGO_SIGNED, TOKEN_ALGO_UNSIGNED, TOKEN_ALGO_BOTH, t);
951                         }
952                 }
953                 ast_log(LOG_DEBUG, "OSP: osp_tokenformat '%d'\n", osp_tokenformat);
954
955                 t = ast_category_browse(cfg, NULL);
956                 while(t) {
957                         if (strcasecmp(t, OSP_GENERAL_CAT)) {
958                                 osp_buildProvider(cfg, t);
959                         }
960                         t = ast_category_browse(cfg, t);
961                 }
962
963                 osp_initialized = 1;
964
965                 ast_config_destroy(cfg);
966         } else {
967                 ast_log(LOG_WARNING, "OSP: Unable to find configuration. OSP support disabled\n");
968         }
969         ast_log(LOG_DEBUG, "OSP: osp_initialized '%d'\n", osp_initialized);
970
971         return(0);
972 }
973
974 static int osp_unload(void)
975 {
976         struct osp_provider* p;
977         struct osp_provider* next;
978
979         if (osp_initialized) {
980                 ast_mutex_lock(&osplock);
981                 p = ospproviders;
982                 while(p) {
983                         next = p->next;
984                         OSPPProviderDelete(p->handle, 0);
985                         free(p);
986                         p = next;
987                 }
988                 ospproviders = NULL;
989                 ast_mutex_unlock(&osplock);
990
991                 OSPPCleanup();
992
993                 osp_usecount = 0;
994                 osp_tokenformat = TOKEN_ALGO_SIGNED;
995                 osp_hardware = 0;
996                 osp_initialized = 0;
997         }
998         return(0);
999 }
1000
1001 static int osp_show(int fd, int argc, char *argv[])
1002 {
1003         int i;
1004         int found = 0;
1005         struct osp_provider* p;
1006         char* provider = NULL;
1007         char* tokenalgo;
1008
1009         if ((argc < 2) || (argc > 3)) {
1010                 return(RESULT_SHOWUSAGE);
1011         }
1012         if (argc > 2) {
1013                 provider = argv[2];
1014         }
1015         if (!provider) {
1016                 switch (osp_tokenformat) {
1017                         case TOKEN_ALGO_BOTH:
1018                                 tokenalgo = "Both";
1019                                 break;
1020                         case TOKEN_ALGO_UNSIGNED:
1021                                 tokenalgo = "Unsigned";
1022                                 break;
1023                         case TOKEN_ALGO_SIGNED:
1024                         default:
1025                                 tokenalgo = "Signed";
1026                                 break;
1027                 }
1028                 ast_cli(fd, "OSP: %s %s %s\n", 
1029                         osp_initialized ? "Initialized" : "Uninitialized", osp_hardware ? "Accelerated" : "Normal", tokenalgo);
1030         }
1031
1032         ast_mutex_lock(&osplock);
1033         p = ospproviders;
1034         while(p) {
1035                 if (!provider || !strcasecmp(p->name, provider)) {
1036                         if (found) {
1037                                 ast_cli(fd, "\n");
1038                         }
1039                         ast_cli(fd, " == OSP Provider '%s' == \n", p->name);
1040                         ast_cli(fd, "Local Private Key: %s\n", p->privatekey);
1041                         ast_cli(fd, "Local Certificate: %s\n", p->localcert);
1042                         for (i = 0; i < p->cacount; i++) {
1043                                 ast_cli(fd, "CA Certificate %d:  %s\n", i + 1, p->cacerts[i]);
1044                         }
1045                         for (i = 0; i < p->spcount; i++) {
1046                                 ast_cli(fd, "Service Point %d:   %s\n", i + 1, p->srvpoints[i]);
1047                         }
1048                         ast_cli(fd, "Max Connections:   %d\n", p->maxconnections);
1049                         ast_cli(fd, "Retry Delay:       %d seconds\n", p->retrydelay);
1050                         ast_cli(fd, "Retry Limit:       %d\n", p->retrylimit);
1051                         ast_cli(fd, "Timeout:           %d milliseconds\n", p->timeout);
1052                         ast_cli(fd, "Source:            %s\n", strlen(p->source) ? p->source : "<unspecified>");
1053                         ast_cli(fd, "Auth Policy        %d\n", p->authpolicy);
1054                         ast_cli(fd, "OSP Handle:        %d\n", p->handle);
1055                         found++;
1056                 }
1057                 p = p->next;
1058         }
1059         ast_mutex_unlock(&osplock);
1060
1061         if (!found) {
1062                 if (provider) {
1063                         ast_cli(fd, "Unable to find OSP provider '%s'\n", provider);
1064                 } else {
1065                         ast_cli(fd, "No OSP providers configured\n");
1066                 }
1067         }
1068         return(RESULT_SUCCESS);
1069 }
1070
1071 static int load_module(void *mod)
1072 {
1073         osp_load();
1074         ast_cli_register(&osp_cli);
1075         return 0;
1076 }
1077
1078 static int reload(void *mod)
1079 {
1080         ast_cli_unregister(&osp_cli);
1081         osp_unload();
1082         osp_load();
1083         ast_cli_register(&osp_cli);
1084         return 0;
1085 }
1086
1087 static int unload_module(void *mod)
1088 {
1089         ast_cli_unregister(&osp_cli);
1090         osp_unload();
1091         return 0;
1092 }
1093
1094 static const char *description(void)
1095 {
1096         return "Open Settlement Protocol Support";
1097 }
1098
1099 #if 0
1100 /* XXX usecount handling still needs to be fixed.
1101  */
1102 int usecount(void)
1103 {
1104         return(osp_usecount);
1105 }
1106 #endif
1107
1108 static const char *key(void)
1109 {
1110         return ASTERISK_GPL_KEY;
1111 }
1112
1113 STD_MOD(MOD_0, reload, NULL, NULL)
1114
1115