d8f437bcb126080ef68ee84f4b41b906d7baf326
[asterisk/asterisk.git] / apps / app_osplookup.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 Open Settlement Protocol (OSP) Applications
22  *
23  * \author Mark Spencer <markster@digium.com>
24  *
25  * \ingroup applications
26  */
27
28 /*** MODULEINFO
29         <depend>osptk</depend>
30         <depend>ssl</depend>
31  ***/
32
33 #include "asterisk.h"
34
35 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
36
37 #include <sys/types.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <errno.h>
42 #include <osp/osp.h>
43 #include <osp/osputils.h>
44
45 #include "asterisk/lock.h"
46 #include "asterisk/config.h"
47 #include "asterisk/utils.h"
48 #include "asterisk/causes.h"
49 #include "asterisk/channel.h"
50 #include "asterisk/app.h"
51 #include "asterisk/module.h"
52 #include "asterisk/pbx.h"
53 #include "asterisk/options.h"
54 #include "asterisk/cli.h"
55 #include "asterisk/logger.h"
56 #include "asterisk/astosp.h"
57
58 /* OSP Buffer Sizes */
59 #define OSP_INTSTR_SIZE         ((unsigned int)16)              /* OSP signed/unsigned int string buffer size */
60 #define OSP_NORSTR_SIZE         ((unsigned int)256)             /* OSP normal string buffer size */
61 #define OSP_TOKSTR_SIZE         ((unsigned int)4096)    /* OSP token string buffer size */
62 #define OSP_TECHSTR_SIZE        ((unsigned int)32)              /* OSP signed/unsigned int string buffer size */
63 #define OSP_UUID_SIZE           ((unsigned int)16)              /* UUID size */
64 #define OSP_UUIDSTR_SIZE        ((unsigned int)36)              /* UUID string size */
65
66 /* OSP Authentication Policy */
67 enum osp_authpolicy {
68         OSP_AUTH_NO,            /* Accept any call */
69         OSP_AUTH_YES,           /* Accept call with valid OSP token or without OSP token */
70         OSP_AUTH_EXCLUSIVE      /* Only accept call with valid OSP token */
71 };
72
73 /* Call ID type*/
74 #define OSP_CALLID_UNDEFINED    ((unsigned int)0)                       /* UNDEFINED */
75 #define OSP_CALLID_H323                 ((unsigned int)(1 << 0))        /* H.323 */
76 #define OSP_CALLID_SIP                  ((unsigned int)(1 << 1))        /* SIP */
77 #define OSP_CALLID_IAX                  ((unsigned int)(1 << 2))        /* IAX2 */
78 #define OSP_CALLID_MAXNUM               ((unsigned int)3)                       /* Max number of call ID type */
79
80 /* OSP Supported Destination Protocols */
81 #define OSP_PROT_H323                   ((char*)"H323")                         /* H323 Q931 protocol name*/
82 #define OSP_PROT_SIP                    ((char*)"SIP")                          /* SIP protocol name */
83 #define OSP_PROT_IAX                    ((char*)"IAX")                          /* IAX protocol name */
84 #define OSP_PROT_OTHER                  ((char*)"OTHER")                        /* Other protocol name */
85
86 /* OSP supported Destination Tech */
87 #if 0
88 #define OSP_TECH_H323                   ((char*)"OOH323")                       /* OOH323 tech name */
89 #endif
90 #define OSP_TECH_H323                   ((char*)"H323")                         /* OH323 tech name */
91 #define OSP_TECH_SIP                    ((char*)"SIP")                          /* SIP tech name */
92 #define OSP_TECH_IAX                    ((char*)"IAX2")                         /* IAX2 tech name */
93
94 /* SIP OSP header field name */
95 #define OSP_SIP_HEADER                  ((char*)"P-OSP-Auth-Token: ")
96
97 /* OSP Constants */
98 #define OSP_INVALID_HANDLE              ((int)-1)                                       /* Invalid OSP handle, provider, transaction etc. */
99 #define OSP_CONFIG_FILE                 ((const char*)"osp.conf")       /* OSP configuration file name */
100 #define OSP_GENERAL_CAT                 ((const char*)"general")        /* OSP global configuration context name */
101 #define OSP_DEF_PROVIDER                ((const char*)"default")        /* OSP default provider context name */
102 #define OSP_MAX_CERTS                   ((unsigned int)10)                      /* OSP max number of cacerts */
103 #define OSP_MAX_SRVS                    ((unsigned int)10)                      /* OSP max number of service points */
104 #define OSP_DEF_MAXCONNECTIONS  ((unsigned int)20)                      /* OSP default max_connections */
105 #define OSP_MIN_MAXCONNECTIONS  ((unsigned int)1)                       /* OSP min max_connections */
106 #define OSP_MAX_MAXCONNECTIONS  ((unsigned int)1000)            /* OSP max max_connections */
107 #define OSP_DEF_RETRYDELAY              ((unsigned int)0)                       /* OSP default retry delay */
108 #define OSP_MIN_RETRYDELAY              ((unsigned int)0)                       /* OSP min retry delay */
109 #define OSP_MAX_RETRYDELAY              ((unsigned int)10)                      /* OSP max retry delay */
110 #define OSP_DEF_RETRYLIMIT              ((unsigned int)2)                       /* OSP default retry times */
111 #define OSP_MIN_RETRYLIMIT              ((unsigned int)0)                       /* OSP min retry times */
112 #define OSP_MAX_RETRYLIMIT              ((unsigned int)100)                     /* OSP max retry times */
113 #define OSP_DEF_TIMEOUT                 ((unsigned int)500)                     /* OSP default timeout in ms */
114 #define OSP_MIN_TIMEOUT                 ((unsigned int)200)                     /* OSP min timeout in ms */
115 #define OSP_MAX_TIMEOUT                 ((unsigned int)10000)           /* OSP max timeout in ms */
116 #define OSP_DEF_AUTHPOLICY              ((enum osp_authpolicy)OSP_AUTH_YES)
117 #define OSP_AUDIT_URL                   ((const char*)"localhost")      /* OSP default Audit URL */
118 #define OSP_LOCAL_VALIDATION    ((int)1)                                        /* Validate OSP token locally */
119 #define OSP_SSL_LIFETIME                ((unsigned int)300)                     /* SSL life time, in seconds */
120 #define OSP_HTTP_PERSISTENCE    ((int)1)                                        /* In seconds */
121 #define OSP_CUSTOMER_ID                 ((const char*)"")                       /* OSP customer ID */
122 #define OSP_DEVICE_ID                   ((const char*)"")                       /* OSP device ID */
123 #define OSP_DEF_DESTINATIONS    ((unsigned int)5)                       /* OSP default max number of destinations */
124 #define OSP_DEF_TIMELIMIT               ((unsigned int)0)                       /* OSP default duration limit, no limit */
125 #define OSP_DEF_PROTOCOL                OSP_PROT_SIP                            /* OSP default destination protocol, SIP */
126
127 /* OSP Provider */
128 struct osp_provider {
129         char name[OSP_NORSTR_SIZE];                                             /* OSP provider context name */
130         char privatekey[OSP_NORSTR_SIZE];                               /* OSP private key file name */
131         char localcert[OSP_NORSTR_SIZE];                                /* OSP local cert file name */
132         unsigned int cacount;                                                   /* Number of cacerts */
133         char cacerts[OSP_MAX_CERTS][OSP_NORSTR_SIZE];   /* Cacert file names */
134         unsigned int spcount;                                                   /* Number of service points */
135         char srvpoints[OSP_MAX_SRVS][OSP_NORSTR_SIZE];  /* Service point URLs */
136         int maxconnections;                                                             /* Max number of connections */
137         int retrydelay;                                                                 /* Retry delay */
138         int retrylimit;                                                                 /* Retry limit */
139         int timeout;                                                                    /* Timeout in ms */
140         char source[OSP_NORSTR_SIZE];                                   /* IP of self */
141         enum osp_authpolicy authpolicy;                                 /* OSP authentication policy */
142         char* defaultprotocol;                                                  /* OSP default destination protocol */
143         OSPTPROVHANDLE handle;                                                  /* OSP provider handle */
144         struct osp_provider* next;                                              /* Pointer to next OSP provider */
145 };
146
147 /* Call ID */
148 struct osp_callid {
149         char buf[OSPC_CALLID_MAXSIZE];          /* Call ID string */
150         unsigned int len;                                       /* Call ID length */
151 };
152
153 /* OSP Application In/Output Results */
154 struct osp_result {
155         int inhandle;                                           /* Inbound transaction handle */
156         int outhandle;                                          /* Outbound transaction handle */
157         unsigned int intimelimit;                       /* Inbound duration limit */
158         unsigned int outtimelimit;                      /* Outbound duration limit */
159         char tech[OSP_TECHSTR_SIZE];            /* Outbound Asterisk TECH string */
160         char dest[OSP_NORSTR_SIZE];                     /* Outbound destination IP address */
161         char called[OSP_NORSTR_SIZE];           /* Outbound called number, may be translated */
162         char calling[OSP_NORSTR_SIZE];          /* Outbound calling number, may be translated */
163         char token[OSP_TOKSTR_SIZE];            /* Outbound OSP token */
164         char networkid[OSP_NORSTR_SIZE];        /* Outbound network ID */
165         unsigned int numresults;                        /* Number of remain outbound destinations */
166         struct osp_callid outcallid;            /* Outbound call ID */
167 };
168
169 /* OSP Module Global Variables */
170 AST_MUTEX_DEFINE_STATIC(osplock);                                                       /* Lock of OSP provider list */
171 static int osp_initialized = 0;                                                         /* Init flag */
172 static int osp_hardware = 0;                                                            /* Hardware accelleration flag */
173 static struct osp_provider* ospproviders = NULL;                        /* OSP provider list */
174 static unsigned int osp_tokenformat = TOKEN_ALGO_SIGNED;        /* Token format supported */
175
176 /* OSP Client Wrapper APIs */
177
178 /*!
179  * \brief Create OSP provider handle according to configuration
180  * \param cfg OSP configuration
181  * \param provider OSP provider context name
182  * \return 1 Success, 0 Failed, -1 Error
183  */
184 static int osp_create_provider(
185         struct ast_config* cfg,
186         const char* provider)
187 {
188         int res;
189         unsigned int t, i, j;
190         struct osp_provider* p;
191         struct ast_variable* v;
192         OSPTPRIVATEKEY privatekey;
193         OSPTCERT localcert;
194         const char* psrvpoints[OSP_MAX_SRVS];
195         OSPTCERT cacerts[OSP_MAX_CERTS];
196         const OSPTCERT* pcacerts[OSP_MAX_CERTS];
197         int error = OSPC_ERR_NO_ERROR;
198
199         if (!(p = ast_calloc(1, sizeof(*p)))) {
200                 ast_log(LOG_ERROR, "Out of memory\n");
201                 return -1;
202         }
203
204         ast_copy_string(p->name, provider, sizeof(p->name));
205         snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s-privatekey.pem", ast_config_AST_KEY_DIR, provider);
206         snprintf(p->localcert, sizeof(p->localcert), "%s/%s-localcert.pem", ast_config_AST_KEY_DIR, provider);
207         p->maxconnections = OSP_DEF_MAXCONNECTIONS;
208         p->retrydelay = OSP_DEF_RETRYDELAY;
209         p->retrylimit = OSP_DEF_RETRYLIMIT;
210         p->timeout = OSP_DEF_TIMEOUT;
211         p->authpolicy = OSP_DEF_AUTHPOLICY;
212         p->defaultprotocol = OSP_DEF_PROTOCOL;
213         p->handle = OSP_INVALID_HANDLE;
214
215         v = ast_variable_browse(cfg, provider);
216         while(v) {
217                 if (!strcasecmp(v->name, "privatekey")) {
218                         if (v->value[0] == '/') {
219                                 ast_copy_string(p->privatekey, v->value, sizeof(p->privatekey));
220                         } else {
221                                 snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s", ast_config_AST_KEY_DIR, v->value);
222                         }
223                         if (option_debug)
224                                 ast_log(LOG_DEBUG, "OSP: privatekey '%s'\n", p->privatekey);
225                 } else if (!strcasecmp(v->name, "localcert")) {
226                         if (v->value[0] == '/') {
227                                 ast_copy_string(p->localcert, v->value, sizeof(p->localcert));
228                         } else {
229                                 snprintf(p->localcert, sizeof(p->localcert), "%s/%s", ast_config_AST_KEY_DIR, v->value);
230                         }
231                         if (option_debug)
232                                 ast_log(LOG_DEBUG, "OSP: localcert '%s'\n", p->localcert);
233                 } else if (!strcasecmp(v->name, "cacert")) {
234                         if (p->cacount < OSP_MAX_CERTS) {
235                                 if (v->value[0] == '/') {
236                                         ast_copy_string(p->cacerts[p->cacount], v->value, sizeof(p->cacerts[0]));
237                                 } else {
238                                         snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s", ast_config_AST_KEY_DIR, v->value);
239                                 }
240                                 if (option_debug)
241                                         ast_log(LOG_DEBUG, "OSP: cacert[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]);
242                                 p->cacount++;
243                         } else {
244                                 ast_log(LOG_WARNING, "OSP: Too many CA Certificates at line %d\n", v->lineno);
245                         }
246                 } else if (!strcasecmp(v->name, "servicepoint")) {
247                         if (p->spcount < OSP_MAX_SRVS) {
248                                 ast_copy_string(p->srvpoints[p->spcount], v->value, sizeof(p->srvpoints[0]));
249                                 if (option_debug)
250                                         ast_log(LOG_DEBUG, "OSP: servicepoint[%d]: '%s'\n", p->spcount, p->srvpoints[p->spcount]);
251                                 p->spcount++;
252                         } else {
253                                 ast_log(LOG_WARNING, "OSP: Too many Service Points at line %d\n", v->lineno);
254                         }
255                 } else if (!strcasecmp(v->name, "maxconnections")) {
256                         if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_MAXCONNECTIONS) && (t <= OSP_MAX_MAXCONNECTIONS)) {
257                                 p->maxconnections = t;
258                                 if (option_debug)
259                                         ast_log(LOG_DEBUG, "OSP: maxconnections '%d'\n", t);
260                         } else {
261                                 ast_log(LOG_WARNING, "OSP: maxconnections should be an integer from %d to %d, not '%s' at line %d\n",
262                                         OSP_MIN_MAXCONNECTIONS, OSP_MAX_MAXCONNECTIONS, v->value, v->lineno);
263                         }
264                 } else if (!strcasecmp(v->name, "retrydelay")) {
265                         if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_RETRYDELAY) && (t <= OSP_MAX_RETRYDELAY)) {
266                                 p->retrydelay = t;
267                                 if (option_debug)
268                                         ast_log(LOG_DEBUG, "OSP: retrydelay '%d'\n", t);
269                         } else {
270                                 ast_log(LOG_WARNING, "OSP: retrydelay should be an integer from %d to %d, not '%s' at line %d\n",
271                                         OSP_MIN_RETRYDELAY, OSP_MAX_RETRYDELAY, v->value, v->lineno);
272                         }
273                 } else if (!strcasecmp(v->name, "retrylimit")) {
274                         if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_RETRYLIMIT) && (t <= OSP_MAX_RETRYLIMIT)) {
275                                 p->retrylimit = t;
276                                 if (option_debug)
277                                         ast_log(LOG_DEBUG, "OSP: retrylimit '%d'\n", t);
278                         } else {
279                                 ast_log(LOG_WARNING, "OSP: retrylimit should be an integer from %d to %d, not '%s' at line %d\n",
280                                         OSP_MIN_RETRYLIMIT, OSP_MAX_RETRYLIMIT, v->value, v->lineno);
281                         }
282                 } else if (!strcasecmp(v->name, "timeout")) {
283                         if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_TIMEOUT) && (t <= OSP_MAX_TIMEOUT)) {
284                                 p->timeout = t;
285                                 if (option_debug)
286                                         ast_log(LOG_DEBUG, "OSP: timeout '%d'\n", t);
287                         } else {
288                                 ast_log(LOG_WARNING, "OSP: timeout should be an integer from %d to %d, not '%s' at line %d\n",
289                                         OSP_MIN_TIMEOUT, OSP_MAX_TIMEOUT, v->value, v->lineno);
290                         }
291                 } else if (!strcasecmp(v->name, "source")) {
292                         ast_copy_string(p->source, v->value, sizeof(p->source));
293                         if (option_debug)
294                                 ast_log(LOG_DEBUG, "OSP: source '%s'\n", p->source);
295                 } else if (!strcasecmp(v->name, "authpolicy")) {
296                         if ((sscanf(v->value, "%d", &t) == 1) && ((t == OSP_AUTH_NO) || (t == OSP_AUTH_YES) || (t == OSP_AUTH_EXCLUSIVE))) {
297                                 p->authpolicy = t;
298                                 if (option_debug)
299                                         ast_log(LOG_DEBUG, "OSP: authpolicy '%d'\n", t);
300                         } else {
301                                 ast_log(LOG_WARNING, "OSP: authpolicy should be %d, %d or %d, not '%s' at line %d\n",
302                                         OSP_AUTH_NO, OSP_AUTH_YES, OSP_AUTH_EXCLUSIVE, v->value, v->lineno);
303                         }
304                 } else if (!strcasecmp(v->name, "defaultprotocol")) {
305                         if (!strcasecmp(v->value, OSP_PROT_SIP)) {
306                                 p->defaultprotocol = OSP_PROT_SIP;
307                                 if (option_debug)
308                                         ast_log(LOG_DEBUG, "OSP: default protocol '%s'\n", p->defaultprotocol);
309                         } else if (!strcasecmp(v->value, OSP_PROT_H323)) {
310                                 p->defaultprotocol = OSP_PROT_H323;
311                                 if (option_debug)
312                                         ast_log(LOG_DEBUG, "OSP: default protocol '%s'\n", p->defaultprotocol);
313                         } else if (!strcasecmp(v->value, OSP_PROT_IAX)) {
314                                 p->defaultprotocol = OSP_PROT_IAX;
315                                 if (option_debug)
316                                         ast_log(LOG_DEBUG, "OSP: default protocol '%s'\n", p->defaultprotocol);
317                         } else {
318                                 ast_log(LOG_WARNING, "OSP: default protocol should be %s, %s, %s, or %s not '%s' at line %d\n",
319                                         OSP_PROT_SIP, OSP_PROT_H323, OSP_PROT_IAX, OSP_PROT_OTHER, v->value, v->lineno);
320                         }
321                 }
322                 v = v->next;
323         }
324
325         error = OSPPUtilLoadPEMPrivateKey((unsigned char*)p->privatekey, &privatekey);
326         if (error != OSPC_ERR_NO_ERROR) {
327                 ast_log(LOG_WARNING, "OSP: Unable to load privatekey '%s', error '%d'\n", p->privatekey, error);
328                 free(p);
329                 return 0;
330         }
331
332         error = OSPPUtilLoadPEMCert((unsigned char*)p->localcert, &localcert);
333         if (error != OSPC_ERR_NO_ERROR) {
334                 ast_log(LOG_WARNING, "OSP: Unable to load localcert '%s', error '%d'\n", p->localcert, error);
335                 if (privatekey.PrivateKeyData) {
336                         free(privatekey.PrivateKeyData);
337                 }
338                 free(p);
339                 return 0;
340         }
341
342         if (p->cacount < 1) {
343                 snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s-cacert.pem", ast_config_AST_KEY_DIR, provider);
344                 if (option_debug)
345                         ast_log(LOG_DEBUG, "OSP: cacert[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]);
346                 p->cacount++;
347         }
348         for (i = 0; i < p->cacount; i++) {
349                 error = OSPPUtilLoadPEMCert((unsigned char*)p->cacerts[i], &cacerts[i]);
350                 if (error != OSPC_ERR_NO_ERROR) {
351                         ast_log(LOG_WARNING, "OSP: Unable to load cacert '%s', error '%d'\n", p->cacerts[i], error);
352                         for (j = 0; j < i; j++) {
353                                 if (cacerts[j].CertData) {
354                                         free(cacerts[j].CertData);
355                                 }
356                         }
357                         if (localcert.CertData) {
358                                 free(localcert.CertData);
359                         }
360                         if (privatekey.PrivateKeyData) {
361                                 free(privatekey.PrivateKeyData);
362                         }
363                         free(p);
364                         return 0;
365                 }
366                 pcacerts[i] = &cacerts[i];
367         }
368
369         for (i = 0; i < p->spcount; i++) {
370                 psrvpoints[i] = p->srvpoints[i];
371         }
372
373         error = OSPPProviderNew(
374                                 p->spcount,
375                                 psrvpoints,
376                                 NULL,
377                                 OSP_AUDIT_URL,
378                                 &privatekey,
379                                 &localcert,
380                                 p->cacount,
381                                 pcacerts,
382                                 OSP_LOCAL_VALIDATION,
383                                 OSP_SSL_LIFETIME,
384                                 p->maxconnections,
385                                 OSP_HTTP_PERSISTENCE,
386                                 p->retrydelay,
387                                 p->retrylimit,
388                                 p->timeout,
389                                 OSP_CUSTOMER_ID,
390                                 OSP_DEVICE_ID,
391                                 &p->handle);
392         if (error != OSPC_ERR_NO_ERROR) {
393                 ast_log(LOG_WARNING, "OSP: Unable to create provider '%s', error '%d'\n", provider, error);
394                 free(p);
395                 res = -1;
396         } else {
397                 if (option_debug)
398                         ast_log(LOG_DEBUG, "OSP: provider '%s'\n", provider);
399                 ast_mutex_lock(&osplock);
400                 p->next = ospproviders;
401                 ospproviders = p;
402                 ast_mutex_unlock(&osplock);
403                 res = 1;
404         }
405
406         for (i = 0; i < p->cacount; i++) {
407                 if (cacerts[i].CertData) {
408                         free(cacerts[i].CertData);
409                 }
410         }
411         if (localcert.CertData) {
412                 free(localcert.CertData);
413         }
414         if (privatekey.PrivateKeyData) {
415                 free(privatekey.PrivateKeyData);
416         }
417
418         return res;
419 }
420
421 /*!
422  * \brief Get OSP provider by name
423  * \param name OSP provider context name
424  * \param provider OSP provider structure
425  * \return 1 Success, 0 Failed, -1 Error
426  */
427 static int osp_get_provider(
428         const char* name,
429         struct osp_provider** provider)
430 {
431         int res = 0;
432         struct osp_provider* p;
433
434         ast_mutex_lock(&osplock);
435         p = ospproviders;
436         while(p) {
437                 if (!strcasecmp(p->name, name)) {
438                         *provider = p;
439                         if (option_debug)
440                                 ast_log(LOG_DEBUG, "OSP: find provider '%s'\n", name);
441                         res = 1;
442                         break;
443                 }
444                 p = p->next;
445         }
446         ast_mutex_unlock(&osplock);
447
448         return res;
449 }
450
451 /*!
452  * \brief Create OSP transaction handle
453  * \param provider OSP provider context name
454  * \param transaction OSP transaction handle, output
455  * \param sourcesize Size of source buffer, in/output
456  * \param source Source of provider, output
457  * \return 1 Success, 0 Failed, -1 Error
458  */
459 static int osp_create_transaction(
460         const char* provider,
461         int* transaction,
462         unsigned int sourcesize,
463         char* source)
464 {
465         int res = 0;
466         struct osp_provider* p;
467         int error;
468
469         ast_mutex_lock(&osplock);
470         p = ospproviders;
471         while(p) {
472                 if (!strcasecmp(p->name, provider)) {
473                         error = OSPPTransactionNew(p->handle, transaction);
474                         if (error == OSPC_ERR_NO_ERROR) {
475                                 if (option_debug)
476                                         ast_log(LOG_DEBUG, "OSP: transaction '%d'\n", *transaction);
477                                 ast_copy_string(source, p->source, sourcesize);
478                                 if (option_debug)
479                                         ast_log(LOG_DEBUG, "OSP: source '%s'\n", source);
480                                 res = 1;
481                         } else {
482                                 *transaction = OSP_INVALID_HANDLE;
483                                 if (option_debug)
484                                         ast_log(LOG_DEBUG, "OSP: Unable to create transaction handle, error '%d'\n", error);
485                                 res = -1;
486                         }
487                         break;
488                 }
489                 p = p->next;
490         }
491         ast_mutex_unlock(&osplock);
492
493         return res;
494 }
495
496 /*!
497  * \brief Convert address to "[x.x.x.x]" or "host.domain" format
498  * \param src Source address string
499  * \param dst Destination address string
500  * \param buffersize Size of dst buffer
501  */
502 static void osp_convert_address(
503         const char* src,
504         char* dst,
505         int buffersize)
506 {
507         struct in_addr inp;
508
509         if (inet_aton(src, &inp) != 0) {
510                 snprintf(dst, buffersize, "[%s]", src);
511         } else {
512                 snprintf(dst, buffersize, "%s", src);
513         }
514 }
515
516 /*!
517  * \brief Validate OSP token of inbound call
518  * \param transaction OSP transaction handle
519  * \param source Source of inbound call
520  * \param destination Destination of inbound call
521  * \param calling Calling number
522  * \param called Called number
523  * \param token OSP token, may be empty
524  * \param timelimit Call duration limit, output
525  * \return 1 Success, 0 Failed, -1 Error
526  */
527 static int osp_validate_token(
528         int transaction,
529         const char* source,
530         const char* destination,
531         const char* calling,
532         const char* called,
533         const char* token,
534         unsigned int* timelimit)
535 {
536         int res;
537         int tokenlen;
538         unsigned char tokenstr[OSP_TOKSTR_SIZE];
539         char src[OSP_TOKSTR_SIZE];
540         char dst[OSP_TOKSTR_SIZE];
541         unsigned int authorised;
542         unsigned int dummy = 0;
543         int error;
544
545         tokenlen = ast_base64decode(tokenstr, token, strlen(token));
546         osp_convert_address(source, src, sizeof(src));
547         osp_convert_address(destination, dst, sizeof(dst));
548         error = OSPPTransactionValidateAuthorisation(
549                                 transaction,
550                                 src,
551                                 dst,
552                                 NULL,
553                                 NULL,
554                                 calling ? calling : "",
555                                 OSPC_E164,
556                                 called,
557                                 OSPC_E164,
558                                 0,
559                                 NULL,
560                                 tokenlen,
561                                 (char*)tokenstr,
562                                 &authorised,
563                                 timelimit,
564                                 &dummy,
565                                 NULL,
566                                 osp_tokenformat);
567         if (error != OSPC_ERR_NO_ERROR) {
568                 if (option_debug)
569                         ast_log(LOG_DEBUG, "OSP: Unable to validate inbound token\n");
570                 res = -1;
571         } else if (authorised) {
572                 if (option_debug)
573                         ast_log(LOG_DEBUG, "OSP: Authorised\n");
574                 res = 1;
575         } else {
576                 if (option_debug)
577                         ast_log(LOG_DEBUG, "OSP: Unauthorised\n");
578                 res = 0;
579         }
580
581         return res;
582 }
583
584 /*!
585  * \brief Choose min duration limit
586  * \param in Inbound duration limit
587  * \param out Outbound duration limit
588  * \return min duration limit
589  */
590 static unsigned int osp_choose_timelimit(
591         unsigned int in,
592         unsigned int out)
593 {
594         if (in == OSP_DEF_TIMELIMIT) {
595                 return out;
596         } else if (out == OSP_DEF_TIMELIMIT) {
597                 return in;
598         } else {
599                 return in < out ? in : out;
600         }
601 }
602
603 /*!
604  * \brief Choose min duration limit
605  * \param provider OSP provider
606  * \param called Called number
607  * \param calling Calling number
608  * \param destination Destination IP in '[x.x.x.x]' format
609  * \param tokenlen OSP token length
610  * \param token OSP token
611  * \param reason Failure reason, output
612  * \param result OSP lookup results, in/output
613  * \return 1 Success, 0 Failed, -1 Error
614  */
615 static int osp_check_destination(
616         struct osp_provider* provider,
617         const char* called,
618         const char* calling,
619         char* destination,
620         unsigned int tokenlen,
621         const char* token,
622         enum OSPEFAILREASON* reason,
623         struct osp_result* result)
624 {
625         int res;
626         OSPE_DEST_OSP_ENABLED enabled;
627         OSPE_DEST_PROT protocol;
628         int error;
629
630         if (strlen(destination) <= 2) {
631                 if (option_debug)
632                         ast_log(LOG_DEBUG, "OSP: Wrong destination format '%s'\n", destination);
633                 *reason = OSPC_FAIL_NORMAL_UNSPECIFIED;
634                 return -1;
635         }
636
637         if ((error = OSPPTransactionIsDestOSPEnabled(result->outhandle, &enabled)) != OSPC_ERR_NO_ERROR) {
638                 if (option_debug)
639                         ast_log(LOG_DEBUG, "OSP: Unable to get destination OSP version, error '%d'\n", error);
640                 *reason = OSPC_FAIL_NORMAL_UNSPECIFIED;
641                 return -1;
642         }
643
644         if (enabled == OSPE_OSP_FALSE) {
645                 result->token[0] = '\0';
646         } else {
647                 ast_base64encode(result->token, (const unsigned char*)token, tokenlen, sizeof(result->token) - 1);
648         }
649
650         if ((error = OSPPTransactionGetDestNetworkId(result->outhandle, result->networkid)) != OSPC_ERR_NO_ERROR) {
651                 if (option_debug)
652                         ast_log(LOG_DEBUG, "OSP: Unable to get destination network ID, error '%d'\n", error);
653                 result->networkid[0] = '\0';
654         }
655
656         if ((error = OSPPTransactionGetDestProtocol(result->outhandle, &protocol)) != OSPC_ERR_NO_ERROR) {
657                 if (option_debug)
658                         ast_log(LOG_DEBUG, "OSP: Unable to get destination protocol, error '%d'\n", error);
659                 *reason = OSPC_FAIL_NORMAL_UNSPECIFIED;
660                 result->token[0] = '\0';
661                 result->networkid[0] = '\0';
662                 return -1;
663         }
664
665         res = 1;
666         /* Strip leading and trailing brackets */
667         destination[strlen(destination) - 1] = '\0';
668         switch(protocol) {
669                 case OSPE_DEST_PROT_H323_SETUP:
670                         if (option_debug)
671                                 ast_log(LOG_DEBUG, "OSP: protocol '%s'\n", OSP_PROT_H323);
672                         ast_copy_string(result->tech, OSP_TECH_H323, sizeof(result->tech));
673                         ast_copy_string(result->dest, destination + 1, sizeof(result->dest));
674                         ast_copy_string(result->called, called, sizeof(result->called));
675                         ast_copy_string(result->calling, calling, sizeof(result->calling));
676                         break;
677                 case OSPE_DEST_PROT_SIP:
678                         if (option_debug)
679                                 ast_log(LOG_DEBUG, "OSP: protocol '%s'\n", OSP_PROT_SIP);
680                         ast_copy_string(result->tech, OSP_TECH_SIP, sizeof(result->tech));
681                         ast_copy_string(result->dest, destination + 1, sizeof(result->dest));
682                         ast_copy_string(result->called, called, sizeof(result->called));
683                         ast_copy_string(result->calling, calling, sizeof(result->calling));
684                         break;
685                 case OSPE_DEST_PROT_IAX:
686                         if (option_debug)
687                                 ast_log(LOG_DEBUG, "OSP: protocol '%s'\n", OSP_PROT_IAX);
688                         ast_copy_string(result->tech, OSP_TECH_IAX, sizeof(result->tech));
689                         ast_copy_string(result->dest, destination + 1, sizeof(result->dest));
690                         ast_copy_string(result->called, called, sizeof(result->called));
691                         ast_copy_string(result->calling, calling, sizeof(result->calling));
692                         break;
693                 case OSPE_DEST_PROT_UNDEFINED:
694                 case OSPE_DEST_PROT_UNKNOWN:
695                         if (option_debug) {
696                                 ast_log(LOG_DEBUG, "OSP: unknown/undefined protocol '%d'\n", protocol);
697                                 ast_log(LOG_DEBUG, "OSP: use default protocol '%s'\n", provider->defaultprotocol);
698                         }
699                         ast_copy_string(result->tech, provider->defaultprotocol, sizeof(result->tech));
700                         ast_copy_string(result->dest, destination + 1, sizeof(result->dest));
701                         ast_copy_string(result->called, called, sizeof(result->called));
702                         ast_copy_string(result->calling, calling, sizeof(result->calling));
703                         break;
704                 case OSPE_DEST_PROT_H323_LRQ:
705                 default:
706                         ast_log(LOG_WARNING, "OSP: unsupported protocol '%d'\n", protocol);
707                         *reason = OSPC_FAIL_PROTOCOL_ERROR;
708                         result->token[0] = '\0';
709                         result->networkid[0] = '\0';
710                         res = 0;
711                         break;
712         }
713
714         return res;
715 }
716
717 /*!
718  * \brief Convert Asterisk status to TC code
719  * \param cause Asterisk hangup cause
720  * \return OSP TC code
721  */
722 static enum OSPEFAILREASON asterisk2osp(
723         int cause)
724 {
725         return (enum OSPEFAILREASON)cause;
726 }
727
728 /*!
729  * \brief OSP Authentication function
730  * \param provider OSP provider context name
731  * \param transaction OSP transaction handle, output
732  * \param source Source of inbound call
733  * \param calling Calling number
734  * \param called Called number
735  * \param token OSP token, may be empty
736  * \param timelimit Call duration limit, output
737  * \return 1 Authenricated, 0 Unauthenticated, -1 Error
738  */
739 static int osp_auth(
740         const char* provider,
741         int* transaction,
742         const char* source,
743         const char* calling,
744         const char* called,
745         const char* token,
746         unsigned int* timelimit)
747 {
748         int res;
749         struct osp_provider* p;
750         char dest[OSP_NORSTR_SIZE];
751
752         *transaction = OSP_INVALID_HANDLE;
753         *timelimit = OSP_DEF_TIMELIMIT;
754
755         if ((res = osp_get_provider(provider, &p)) <= 0) {
756                 if (option_debug)
757                         ast_log(LOG_DEBUG, "OSP: Unabe to find OSP provider '%s'\n", provider);
758                 return res;
759         }
760
761         switch (p->authpolicy) {
762                 case OSP_AUTH_NO:
763                         res = 1;
764                         break;
765                 case OSP_AUTH_EXCLUSIVE:
766                         if (ast_strlen_zero(token)) {
767                                 res = 0;
768                         } else if ((res = osp_create_transaction(provider, transaction, sizeof(dest), dest)) <= 0) {
769                                 if (option_debug)
770                                         ast_log(LOG_DEBUG, "OSP: Unable to generate transaction handle\n");
771                                 *transaction = OSP_INVALID_HANDLE;
772                                 res = 0;
773                         } else if((res = osp_validate_token(*transaction, source, dest, calling, called, token, timelimit)) <= 0) {
774                                 OSPPTransactionRecordFailure(*transaction, OSPC_FAIL_CALL_REJECTED);
775                         }
776                         break;
777                 case OSP_AUTH_YES:
778                 default:
779                         if (ast_strlen_zero(token)) {
780                                 res = 1;
781                         } else if ((res = osp_create_transaction(provider, transaction, sizeof(dest), dest)) <= 0) {
782                                 if (option_debug)
783                                         ast_log(LOG_DEBUG, "OSP: Unable to generate transaction handle\n");
784                                 *transaction = OSP_INVALID_HANDLE;
785                                 res = 0;
786                         } else if((res = osp_validate_token(*transaction, source, dest, calling, called, token, timelimit)) <= 0) {
787                                 OSPPTransactionRecordFailure(*transaction, OSPC_FAIL_CALL_REJECTED);
788                         }
789                         break;
790         }
791
792         return res;
793 }
794
795 /*!
796  * \brief Create a UUID
797  * \param uuid UUID buffer
798  * \param buffersize UUID buffer size
799  * \return 1 Created, -1 Error
800  */
801 static int osp_create_uuid(
802         unsigned char* uuid,
803         unsigned int* buffersize)
804 {
805         int i, res;
806         long int* tmp;
807
808         if (*buffersize >= OSP_UUID_SIZE) {
809                 tmp = (long int*)uuid;
810                 for (i = 0; i < OSP_UUID_SIZE / sizeof(long int); i++) {
811                         tmp[i] = ast_random();
812                 }
813                 *buffersize = OSP_UUID_SIZE;
814                 res = 1;
815         } else {
816                 res = -1;
817         }
818
819         return res;
820 }
821
822 /*!
823  * \brief UUID to string
824  * \param uuid UUID
825  * \param buffer String buffer
826  * \param buffersize String buffer size
827  * \return 1 Successed, -1 Error
828  */
829 static int osp_uuid2str(
830         unsigned char* uuid,
831         char* buffer,
832         unsigned int buffersize)
833 {
834         int res;
835
836         if (buffersize > OSP_UUIDSTR_SIZE) {
837                 snprintf(buffer, buffersize, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
838                         uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],
839                         uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
840                 res = 1;
841         } else {
842                 res = -1;
843         }
844
845         return res;
846 }
847
848 /*!
849  * \brief Create a call ID according to the type
850  * \param type Call ID type
851  * \param callid Call ID buffer
852  * \return 1 Created, 0 Not create, -1 Error
853  */
854 static int osp_create_callid(
855         unsigned int type,
856         struct osp_callid* callid)
857 {
858         int res;
859
860         callid->len = sizeof(callid->buf);
861         switch (type) {
862                 case OSP_CALLID_H323:
863                         res = osp_create_uuid(callid->buf, &callid->len);
864                         break;
865                 case OSP_CALLID_SIP:
866                 case OSP_CALLID_IAX:
867                         res = 0;
868                 default:
869                         res = -1;
870                         break;
871         }
872
873         if ((res != 1) && (callid->len != 0)) {
874                 callid->buf[0] = '\0';
875                 callid->len = 0;
876         }
877
878         return res;
879 }
880
881 /*!
882  * \brief OSP Lookup function
883  * \param provider OSP provider context name
884  * \param srcdev Source device of outbound call
885  * \param calling Calling number
886  * \param called Called number
887  * \param callidtypes Call ID types
888  * \param result Lookup results
889  * \return 1 Found , 0 No route, -1 Error
890  */
891 static int osp_lookup(
892         const char* provider,
893         const char* srcdev,
894         const char* calling,
895         const char* called,
896         unsigned int callidtypes,
897         struct osp_result* result)
898 {
899         int res;
900         struct osp_provider* p;
901         char source[OSP_NORSTR_SIZE];
902         char callingnum[OSP_NORSTR_SIZE];
903         char callednum[OSP_NORSTR_SIZE];
904         char destination[OSP_NORSTR_SIZE];
905         unsigned int tokenlen;
906         char token[OSP_TOKSTR_SIZE];
907         char src[OSP_NORSTR_SIZE];
908         char dev[OSP_NORSTR_SIZE];
909         unsigned int i, type;
910         struct osp_callid callid;
911         unsigned int callidnum;
912         OSPTCALLID* callids[OSP_CALLID_MAXNUM];
913         unsigned int dummy = 0;
914         enum OSPEFAILREASON reason;
915         int error;
916
917         result->outhandle = OSP_INVALID_HANDLE;
918         result->tech[0] = '\0';
919         result->dest[0] = '\0';
920         result->called[0] = '\0';
921         result->calling[0] = '\0';
922         result->token[0] = '\0';
923         result->networkid[0] = '\0';
924         result->numresults = 0;
925         result->outtimelimit = OSP_DEF_TIMELIMIT;
926
927         if ((res = osp_get_provider(provider, &p)) <= 0) {
928                 if (option_debug)
929                         ast_log(LOG_DEBUG, "OSP: Unabe to find OSP provider '%s'\n", provider);
930                 return res;
931         }
932
933         if ((res = osp_create_transaction(provider, &result->outhandle, sizeof(source), source)) <= 0) {
934                 if (option_debug)
935                         ast_log(LOG_DEBUG, "OSP: Unable to generate transaction handle\n");
936                 result->outhandle = OSP_INVALID_HANDLE;
937                 if (result->inhandle != OSP_INVALID_HANDLE) {
938                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
939                 }
940                 return -1;
941         }
942
943         callidnum = 0;
944         callids[0] = NULL;
945         for (i = 0; i < OSP_CALLID_MAXNUM; i++) {
946                 type = 1 << i;
947                 if (callidtypes & type) {
948                         error = osp_create_callid(type, &callid);
949                         if (error == 1) {
950                                 callids[callidnum] = OSPPCallIdNew(callid.len, callid.buf);
951                                 callidnum++;
952                         }
953                 }
954         }
955
956         osp_convert_address(source, src, sizeof(src));
957         osp_convert_address(srcdev, dev, sizeof(dev));
958         result->numresults = OSP_DEF_DESTINATIONS;
959         error = OSPPTransactionRequestAuthorisation(
960                                 result->outhandle,
961                                 src,
962                                 dev,
963                                 calling ? calling : "",
964                                 OSPC_E164,
965                                 called,
966                                 OSPC_E164,
967                                 NULL,
968                                 callidnum,
969                                 callids,
970                                 NULL,
971                                 &result->numresults,
972                                 &dummy,
973                                 NULL);
974
975         for (i = 0; i < callidnum; i++) {
976                 OSPPCallIdDelete(&callids[i]);
977         }
978
979         if (error != OSPC_ERR_NO_ERROR) {
980                 if (option_debug)
981                         ast_log(LOG_DEBUG, "OSP: Unable to request authorization\n");
982                 result->numresults = 0;
983                 if (result->inhandle != OSP_INVALID_HANDLE) {
984                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
985                 }
986                 return -1;
987         }
988
989         if (!result->numresults) {
990                 if (option_debug)
991                         ast_log(LOG_DEBUG, "OSP: No more destination\n");
992                 if (result->inhandle != OSP_INVALID_HANDLE) {
993                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
994                 }
995                 return 0;
996         }
997
998         result->outcallid.len = sizeof(result->outcallid.buf);
999         tokenlen = sizeof(token);
1000         error = OSPPTransactionGetFirstDestination(
1001                                 result->outhandle,
1002                                 0,
1003                                 NULL,
1004                                 NULL,
1005                                 &result->outtimelimit,
1006                                 &result->outcallid.len,
1007                                 result->outcallid.buf,
1008                                 sizeof(callednum),
1009                                 callednum,
1010                                 sizeof(callingnum),
1011                                 callingnum,
1012                                 sizeof(destination),
1013                                 destination,
1014                                 0,
1015                                 NULL,
1016                                 &tokenlen,
1017                                 token);
1018         if (error != OSPC_ERR_NO_ERROR) {
1019                 if (option_debug)
1020                         ast_log(LOG_DEBUG, "OSP: Unable to get first route\n");
1021                 result->numresults = 0;
1022                 result->outtimelimit = OSP_DEF_TIMELIMIT;
1023                 if (result->inhandle != OSP_INVALID_HANDLE) {
1024                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1025                 }
1026                 return -1;
1027         }
1028
1029         result->numresults--;
1030         result->outtimelimit = osp_choose_timelimit(result->intimelimit, result->outtimelimit);
1031         if (option_debug) {
1032                 ast_log(LOG_DEBUG, "OSP: outtimelimit '%d'\n", result->outtimelimit);
1033                 ast_log(LOG_DEBUG, "OSP: called '%s'\n", callednum);
1034                 ast_log(LOG_DEBUG, "OSP: calling '%s'\n", callingnum);
1035                 ast_log(LOG_DEBUG, "OSP: destination '%s'\n", destination);
1036                 ast_log(LOG_DEBUG, "OSP: token size '%d'\n", tokenlen);
1037         }
1038
1039         if ((res = osp_check_destination(p, callednum, callingnum, destination, tokenlen, token, &reason, result)) > 0) {
1040                 return 1;
1041         }
1042
1043         if (!result->numresults) {
1044                 if (option_debug)
1045                         ast_log(LOG_DEBUG, "OSP: No more destination\n");
1046                 result->outtimelimit = OSP_DEF_TIMELIMIT;
1047                 OSPPTransactionRecordFailure(result->outhandle, reason);
1048                 if (result->inhandle != OSP_INVALID_HANDLE) {
1049                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1050                 }
1051                 return 0;
1052         }
1053
1054         while(result->numresults) {
1055                 result->outcallid.len = sizeof(result->outcallid.buf);
1056                 tokenlen = sizeof(token);
1057                 error = OSPPTransactionGetNextDestination(
1058                                         result->outhandle,
1059                                         reason,
1060                                         0,
1061                                         NULL,
1062                                         NULL,
1063                                         &result->outtimelimit,
1064                                         &result->outcallid.len,
1065                                         result->outcallid.buf,
1066                                         sizeof(callednum),
1067                                         callednum,
1068                                         sizeof(callingnum),
1069                                         callingnum,
1070                                         sizeof(destination),
1071                                         destination,
1072                                         0,
1073                                         NULL,
1074                                         &tokenlen,
1075                                         token);
1076                 if (error == OSPC_ERR_NO_ERROR) {
1077                         result->numresults--;
1078                         result->outtimelimit = osp_choose_timelimit(result->intimelimit, result->outtimelimit);
1079                         if (option_debug) {
1080                                 ast_log(LOG_DEBUG, "OSP: outtimelimit '%d'\n", result->outtimelimit);
1081                                 ast_log(LOG_DEBUG, "OSP: called '%s'\n", callednum);
1082                                 ast_log(LOG_DEBUG, "OSP: calling '%s'\n", callingnum);
1083                                 ast_log(LOG_DEBUG, "OSP: destination '%s'\n", destination);
1084                                 ast_log(LOG_DEBUG, "OSP: token size '%d'\n", tokenlen);
1085                         }
1086                         if ((res = osp_check_destination(p, callednum, callingnum, destination, tokenlen, token, &reason, result)) > 0) {
1087                                 break;
1088                         } else if (!result->numresults) {
1089                                 if (option_debug)
1090                                         ast_log(LOG_DEBUG, "OSP: No more destination\n");
1091                                 OSPPTransactionRecordFailure(result->outhandle, reason);
1092                                 if (result->inhandle != OSP_INVALID_HANDLE) {
1093                                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1094                                 }
1095                                 res = 0;
1096                                 break;
1097                         }
1098                 } else {
1099                         if (option_debug)
1100                                 ast_log(LOG_DEBUG, "OSP: Unable to get route, error '%d'\n", error);
1101                         result->numresults = 0;
1102                         result->outtimelimit = OSP_DEF_TIMELIMIT;
1103                         if (result->inhandle != OSP_INVALID_HANDLE) {
1104                                 OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
1105                         }
1106                         res = -1;
1107                         break;
1108                 }
1109         }
1110         return res;
1111 }
1112
1113 /*!
1114  * \brief OSP Lookup Next function
1115  * \param cause Asterisk hangup cuase
1116  * \param result Lookup results, in/output
1117  * \return 1 Found , 0 No route, -1 Error
1118  */
1119 static int osp_next(
1120         const char* provider,
1121         int cause,
1122         struct osp_result* result)
1123 {
1124         int res;
1125         struct osp_provider* p;
1126         char callingnum[OSP_NORSTR_SIZE];
1127         char callednum[OSP_NORSTR_SIZE];
1128         char destination[OSP_NORSTR_SIZE];
1129         unsigned int tokenlen;
1130         char token[OSP_TOKSTR_SIZE];
1131         enum OSPEFAILREASON reason;
1132         int error;
1133
1134         result->tech[0] = '\0';
1135         result->dest[0] = '\0';
1136         result->called[0] = '\0';
1137         result->calling[0] = '\0';
1138         result->token[0] = '\0';
1139         result->networkid[0] = '\0';
1140         result->outtimelimit = OSP_DEF_TIMELIMIT;
1141
1142         if ((res = osp_get_provider(provider, &p)) <= 0) {
1143                 if (option_debug)
1144                         ast_log(LOG_DEBUG, "OSP: Unabe to find OSP provider '%s'\n", provider);
1145                 return res;
1146         }
1147
1148         if (result->outhandle == OSP_INVALID_HANDLE) {
1149                 if (option_debug)
1150                         ast_log(LOG_DEBUG, "OSP: Transaction handle undefined\n");
1151                 result->numresults = 0;
1152                 if (result->inhandle != OSP_INVALID_HANDLE) {
1153                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
1154                 }
1155                 return -1;
1156         }
1157
1158         reason = asterisk2osp(cause);
1159
1160         if (!result->numresults) {
1161                 if (option_debug)
1162                         ast_log(LOG_DEBUG, "OSP: No more destination\n");
1163                 OSPPTransactionRecordFailure(result->outhandle, reason);
1164                 if (result->inhandle != OSP_INVALID_HANDLE) {
1165                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1166                 }
1167                 return 0;
1168         }
1169
1170         while(result->numresults) {
1171                 result->outcallid.len = sizeof(result->outcallid.buf);
1172                 tokenlen = sizeof(token);
1173                 error = OSPPTransactionGetNextDestination(
1174                                         result->outhandle,
1175                                         reason,
1176                                         0,
1177                                         NULL,
1178                                         NULL,
1179                                         &result->outtimelimit,
1180                                         &result->outcallid.len,
1181                                         result->outcallid.buf,
1182                                         sizeof(callednum),
1183                                         callednum,
1184                                         sizeof(callingnum),
1185                                         callingnum,
1186                                         sizeof(destination),
1187                                         destination,
1188                                         0,
1189                                         NULL,
1190                                         &tokenlen,
1191                                         token);
1192                 if (error == OSPC_ERR_NO_ERROR) {
1193                         result->numresults--;
1194                         result->outtimelimit = osp_choose_timelimit(result->intimelimit, result->outtimelimit);
1195                         if (option_debug) {
1196                                 ast_log(LOG_DEBUG, "OSP: outtimelimit '%d'\n", result->outtimelimit);
1197                                 ast_log(LOG_DEBUG, "OSP: called '%s'\n", callednum);
1198                                 ast_log(LOG_DEBUG, "OSP: calling '%s'\n", callingnum);
1199                                 ast_log(LOG_DEBUG, "OSP: destination '%s'\n", destination);
1200                                 ast_log(LOG_DEBUG, "OSP: token size '%d'\n", tokenlen);
1201                         }
1202                         if ((res = osp_check_destination(p, callednum, callingnum, destination, tokenlen, token, &reason, result)) > 0) {
1203                                 res = 1;
1204                                 break;
1205                         } else if (!result->numresults) {
1206                                 if (option_debug)
1207                                         ast_log(LOG_DEBUG, "OSP: No more destination\n");
1208                                 OSPPTransactionRecordFailure(result->outhandle, reason);
1209                                 if (result->inhandle != OSP_INVALID_HANDLE) {
1210                                         OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
1211                                 }
1212                                 res = 0;
1213                                 break;
1214                         }
1215                 } else {
1216                         if (option_debug)
1217                                 ast_log(LOG_DEBUG, "OSP: Unable to get route, error '%d'\n", error);
1218                         result->token[0] = '\0';
1219                         result->numresults = 0;
1220                         result->outtimelimit = OSP_DEF_TIMELIMIT;
1221                         if (result->inhandle != OSP_INVALID_HANDLE) {
1222                                 OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
1223                         }
1224                         res = -1;
1225                         break;
1226                 }
1227         }
1228
1229         return res;
1230 }
1231
1232 /*!
1233  * \brief OSP Finish function
1234  * \param handle OSP in/outbound transaction handle
1235  * \param recorded If failure reason has been recorded
1236  * \param cause Asterisk hangup cause
1237  * \param start Call start time
1238  * \param connect Call connect time
1239  * \param end Call end time
1240  * \param release Who release first, 0 source, 1 destination
1241  * \return 1 Success, 0 Failed, -1 Error
1242  */
1243 static int osp_finish(
1244         int handle,
1245         int recorded,
1246         int cause,
1247         time_t start,
1248         time_t connect,
1249         time_t end,
1250         unsigned int release)
1251 {
1252         int res;
1253         enum OSPEFAILREASON reason;
1254         time_t alert = 0;
1255         unsigned isPddInfoPresent = 0;
1256         unsigned pdd = 0;
1257         unsigned int dummy = 0;
1258         int error;
1259
1260         if (handle == OSP_INVALID_HANDLE) {
1261                 return 0;
1262         }
1263
1264         if (!recorded) {
1265                 reason = asterisk2osp(cause);
1266                 OSPPTransactionRecordFailure(handle, reason);
1267         }
1268
1269         error = OSPPTransactionReportUsage(
1270                                 handle,
1271                                 difftime(end, connect),
1272                                 start,
1273                                 end,
1274                                 alert,
1275                                 connect,
1276                                 isPddInfoPresent,
1277                                 pdd,
1278                                 release,
1279                                 (unsigned char*)"",
1280                                 0,
1281                                 0,
1282                                 0,
1283                                 0,
1284                                 &dummy,
1285                                 NULL);
1286         if (error == OSPC_ERR_NO_ERROR) {
1287                 if (option_debug)
1288                         ast_log(LOG_DEBUG, "OSP: Usage reported\n");
1289                 res = 1;
1290         } else {
1291                 if (option_debug)
1292                         ast_log(LOG_DEBUG, "OSP: Unable to report usage, error '%d'\n", error);
1293                 res = -1;
1294         }
1295         OSPPTransactionDelete(handle);
1296
1297         return res;
1298 }
1299
1300 /* OSP Application APIs */
1301
1302 /*!
1303  * \brief OSP Application OSPAuth
1304  * \param chan Channel
1305  * \param data Parameter
1306  * \return 0 Success, -1 Failed
1307  */
1308 static int ospauth_exec(
1309         struct ast_channel* chan,
1310         void* data)
1311 {
1312         int res;
1313         struct ast_module_user* u;
1314         const char* provider = OSP_DEF_PROVIDER;
1315         int priority_jump = 0;
1316         struct varshead* headp;
1317         struct ast_var_t* current;
1318         const char* source = "";
1319         const char* token = "";
1320         int handle;
1321         unsigned int timelimit;
1322         char buffer[OSP_INTSTR_SIZE];
1323         const char* status;
1324         char* tmp;
1325
1326         AST_DECLARE_APP_ARGS(args,
1327                 AST_APP_ARG(provider);
1328                 AST_APP_ARG(options);
1329         );
1330
1331         u = ast_module_user_add(chan);
1332
1333         if (!(tmp = ast_strdupa(data))) {
1334                 ast_log(LOG_ERROR, "Out of memory\n");
1335                 ast_module_user_remove(u);
1336                 return -1;
1337         }
1338
1339         AST_STANDARD_APP_ARGS(args, tmp);
1340
1341         if (!ast_strlen_zero(args.provider)) {
1342                 provider = args.provider;
1343         }
1344         if (option_debug)
1345                 ast_log(LOG_DEBUG, "OSPAuth: provider '%s'\n", provider);
1346
1347         if ((args.options) && (strchr(args.options, 'j'))) {
1348                 priority_jump = 1;
1349         }
1350         if (option_debug)
1351                 ast_log(LOG_DEBUG, "OSPAuth: priority jump '%d'\n", priority_jump);
1352
1353         headp = &chan->varshead;
1354         AST_LIST_TRAVERSE(headp, current, entries) {
1355                 if (!strcasecmp(ast_var_name(current), "OSPPEERIP")) {
1356                         source = ast_var_value(current);
1357                 } else if (!strcasecmp(ast_var_name(current), "OSPINTOKEN")) {
1358                         token = ast_var_value(current);
1359                 }
1360         }
1361
1362         if (option_debug) {
1363                 ast_log(LOG_DEBUG, "OSPAuth: source '%s'\n", source);
1364                 ast_log(LOG_DEBUG, "OSPAuth: token size '%zd'\n", strlen(token));
1365         }
1366
1367         if ((res = osp_auth(provider, &handle, source, chan->cid.cid_num, chan->exten, token, &timelimit)) > 0) {
1368                 status = AST_OSP_SUCCESS;
1369         } else {
1370                 timelimit = OSP_DEF_TIMELIMIT;
1371                 if (!res) {
1372                         status = AST_OSP_FAILED;
1373                 } else {
1374                         status = AST_OSP_ERROR;
1375                 }
1376         }
1377
1378         snprintf(buffer, sizeof(buffer), "%d", handle);
1379         pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer);
1380         if (option_debug)
1381                 ast_log(LOG_DEBUG, "OSPAuth: OSPINHANDLE '%s'\n", buffer);
1382         snprintf(buffer, sizeof(buffer), "%d", timelimit);
1383         pbx_builtin_setvar_helper(chan, "OSPINTIMELIMIT", buffer);
1384         if (option_debug)
1385                 ast_log(LOG_DEBUG, "OSPAuth: OSPINTIMELIMIT '%s'\n", buffer);
1386         pbx_builtin_setvar_helper(chan, "OSPAUTHSTATUS", status);
1387         if (option_debug)
1388                 ast_log(LOG_DEBUG, "OSPAuth: %s\n", status);
1389
1390         if(res <= 0) {
1391                 if (priority_jump || ast_opt_priority_jumping) {
1392                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
1393                         res = 0;
1394                 } else {
1395                         res = -1;
1396                 }
1397         } else {
1398                 res = 0;
1399         }
1400
1401         ast_module_user_remove(u);
1402
1403         return res;
1404 }
1405
1406 /*!
1407  * \brief OSP Application OSPLookup
1408  * \param chan Channel
1409  * \param data Parameter
1410  * \return 0 Success, -1 Failed
1411  */
1412 static int osplookup_exec(
1413         struct ast_channel* chan,
1414         void* data)
1415 {
1416         int res, cres;
1417         struct ast_module_user* u;
1418         const char* provider = OSP_DEF_PROVIDER;
1419         int priority_jump = 0;
1420         struct varshead* headp;
1421         struct ast_var_t* current;
1422         const char* srcdev = "";
1423         const char* netid = "";
1424         char buffer[OSP_TOKSTR_SIZE];
1425         unsigned int callidtypes = OSP_CALLID_UNDEFINED;
1426         struct osp_result result;
1427         const char* status;
1428         char* tmp;
1429
1430         AST_DECLARE_APP_ARGS(args,
1431                 AST_APP_ARG(exten);
1432                 AST_APP_ARG(provider);
1433                 AST_APP_ARG(options);
1434         );
1435
1436         if (ast_strlen_zero(data)) {
1437                 ast_log(LOG_WARNING, "OSPLookup: Arg required, OSPLookup(exten[|provider[|options]])\n");
1438                 return -1;
1439         }
1440
1441         u = ast_module_user_add(chan);
1442
1443         if (!(tmp = ast_strdupa(data))) {
1444                 ast_log(LOG_ERROR, "Out of memory\n");
1445                 ast_module_user_remove(u);
1446                 return -1;
1447         }
1448
1449         AST_STANDARD_APP_ARGS(args, tmp);
1450
1451         if (option_debug)
1452                 ast_log(LOG_DEBUG, "OSPLookup: exten '%s'\n", args.exten);
1453
1454         if (!ast_strlen_zero(args.provider)) {
1455                 provider = args.provider;
1456         }
1457         if (option_debug)
1458                 ast_log(LOG_DEBUG, "OSPlookup: provider '%s'\n", provider);
1459
1460         if (args.options) {
1461                 if (strchr(args.options, 'j')) {
1462                         priority_jump = 1;
1463                 }
1464                 if (strchr(args.options, 'h')) {
1465                         callidtypes |= OSP_CALLID_H323;
1466                 }
1467                 if (strchr(args.options, 's')) {
1468                         callidtypes |= OSP_CALLID_SIP;
1469                 }
1470                 if (strchr(args.options, 'i')) {
1471                         callidtypes |= OSP_CALLID_IAX;
1472                 }
1473         }
1474         if (option_debug) {
1475                 ast_log(LOG_DEBUG, "OSPLookup: priority jump '%d'\n", priority_jump);
1476                 ast_log(LOG_DEBUG, "OSPLookup: call id types '%d'\n", callidtypes);
1477         }
1478
1479         result.inhandle = OSP_INVALID_HANDLE;
1480         result.intimelimit = OSP_DEF_TIMELIMIT;
1481
1482         headp = &chan->varshead;
1483         AST_LIST_TRAVERSE(headp, current, entries) {
1484                 if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
1485                         if (sscanf(ast_var_value(current), "%d", &result.inhandle) != 1) {
1486                                 result.inhandle = OSP_INVALID_HANDLE;
1487                         }
1488                 } else if (!strcasecmp(ast_var_name(current), "OSPINTIMELIMIT")) {
1489                         if (sscanf(ast_var_value(current), "%d", &result.intimelimit) != 1) {
1490                                 result.intimelimit = OSP_DEF_TIMELIMIT;
1491                         }
1492                 } else if (!strcasecmp(ast_var_name(current), "OSPINNETWORKID")) {
1493                         netid = ast_var_value(current);
1494                 } else if (!strcasecmp(ast_var_name(current), "OSPPEERIP")) {
1495                         srcdev = ast_var_value(current);
1496                 }
1497         }
1498         if (option_debug) {
1499                 ast_log(LOG_DEBUG, "OSPLookup: OSPINHANDLE '%d'\n", result.inhandle);
1500                 ast_log(LOG_DEBUG, "OSPLookup: OSPINTIMELIMIT '%d'\n", result.intimelimit);
1501                 ast_log(LOG_DEBUG, "OSPLookup: OSPINNETWORKID '%s'\n", netid);
1502                 ast_log(LOG_DEBUG, "OSPLookup: source device '%s'\n", srcdev);
1503         }
1504
1505         if ((cres = ast_autoservice_start(chan)) < 0) {
1506                 ast_module_user_remove(u);
1507                 return -1;
1508         }
1509
1510         if ((res = osp_lookup(provider, srcdev, chan->cid.cid_num, args.exten, callidtypes, &result)) > 0) {
1511                 status = AST_OSP_SUCCESS;
1512         } else {
1513                 result.tech[0] = '\0';
1514                 result.dest[0] = '\0';
1515                 result.called[0] = '\0';
1516                 result.calling[0] = '\0';
1517                 result.token[0] = '\0';
1518                 result.networkid[0] = '\0';
1519                 result.numresults = 0;
1520                 result.outtimelimit = OSP_DEF_TIMELIMIT;
1521                 result.outcallid.buf[0] = '\0';
1522                 result.outcallid.len = 0;
1523                 if (!res) {
1524                         status = AST_OSP_FAILED;
1525                 } else {
1526                         status = AST_OSP_ERROR;
1527                 }
1528         }
1529
1530         snprintf(buffer, sizeof(buffer), "%d", result.outhandle);
1531         pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer);
1532         if (option_debug)
1533                 ast_log(LOG_DEBUG, "OSPLookup: OSPOUTHANDLE '%s'\n", buffer);
1534         pbx_builtin_setvar_helper(chan, "OSPTECH", result.tech);
1535         if (option_debug)
1536                 ast_log(LOG_DEBUG, "OSPLookup: OSPTECH '%s'\n", result.tech);
1537         pbx_builtin_setvar_helper(chan, "OSPDEST", result.dest);
1538         if (option_debug)
1539                 ast_log(LOG_DEBUG, "OSPLookup: OSPDEST '%s'\n", result.dest);
1540         pbx_builtin_setvar_helper(chan, "OSPCALLED", result.called);
1541         if (option_debug)
1542                 ast_log(LOG_DEBUG, "OSPLookup: OSPCALLED '%s'\n", result.called);
1543         pbx_builtin_setvar_helper(chan, "OSPCALLING", result.calling);
1544         if (option_debug)
1545                 ast_log(LOG_DEBUG, "OSPLookup: OSPCALLING '%s'\n", result.calling);
1546         pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", result.token);
1547         if (option_debug)
1548                 ast_log(LOG_DEBUG, "OSPLookup: OSPOUTTOKEN size '%zd'\n", strlen(result.token));
1549         snprintf(buffer, sizeof(buffer), "%d", result.numresults);
1550         pbx_builtin_setvar_helper(chan, "OSPRESULTS", buffer);
1551         if (option_debug)
1552                 ast_log(LOG_DEBUG, "OSPLookup: OSPRESULTS '%s'\n", buffer);
1553         snprintf(buffer, sizeof(buffer), "%d", result.outtimelimit);
1554         pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer);
1555         if (option_debug)
1556                 ast_log(LOG_DEBUG, "OSPLookup: OSPOUTTIMELIMIT '%s'\n", buffer);
1557         snprintf(buffer, sizeof(buffer), "%d", callidtypes);
1558         pbx_builtin_setvar_helper(chan, "OSPOUTCALLIDTYPES", buffer);
1559         if (option_debug)
1560                 ast_log(LOG_DEBUG, "OSPLookup: OSPOUTCALLIDTYPES '%s'\n", buffer);
1561         pbx_builtin_setvar_helper(chan, "OSPLOOKUPSTATUS", status);
1562         if (option_debug)
1563                 ast_log(LOG_DEBUG, "OSPLookup: %s\n", status);
1564
1565         if (!strcasecmp(result.tech, OSP_TECH_H323)) {
1566                 if ((callidtypes & OSP_CALLID_H323) && (result.outcallid.len != 0)) {
1567                         osp_uuid2str(result.outcallid.buf, buffer, sizeof(buffer));
1568                 } else {
1569                         buffer[0] = '\0';
1570                 }
1571                 pbx_builtin_setvar_helper(chan, "OSPOUTCALLID", buffer);
1572                 snprintf(buffer, sizeof(buffer), "%s/%s@%s", result.tech, result.called, result.dest);
1573                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
1574         } else if (!strcasecmp(result.tech, OSP_TECH_SIP)) {
1575                 snprintf(buffer, sizeof(buffer), "%s/%s@%s", result.tech, result.called, result.dest);
1576                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
1577                 if (!ast_strlen_zero(result.token)) {
1578                         snprintf(buffer, sizeof(buffer), "%s%s", OSP_SIP_HEADER, result.token);
1579                         pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer);
1580                         if (option_debug)
1581                                 ast_log(LOG_DEBUG, "OSPLookup: SIPADDHEADER size '%zd'\n", strlen(buffer));
1582                 }
1583         } else if (!strcasecmp(result.tech, OSP_TECH_IAX)) {
1584                 snprintf(buffer, sizeof(buffer), "%s/%s/%s", result.tech, result.dest, result.called);
1585                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
1586         }
1587
1588         if ((cres = ast_autoservice_stop(chan)) < 0) {
1589                 ast_module_user_remove(u);
1590                 return -1;
1591         }
1592
1593         if(res <= 0) {
1594                 if (priority_jump || ast_opt_priority_jumping) {
1595                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
1596                         res = 0;
1597                 } else {
1598                         res = -1;
1599                 }
1600         } else {
1601                 res = 0;
1602         }
1603
1604         ast_module_user_remove(u);
1605
1606         return res;
1607 }
1608
1609 /*!
1610  * \brief OSP Application OSPNext
1611  * \param chan Channel
1612  * \param data Parameter
1613  * \return 0 Success, -1 Failed
1614  */
1615 static int ospnext_exec(
1616         struct ast_channel* chan,
1617         void* data)
1618 {
1619         int res;
1620         struct ast_module_user* u;
1621         const char* provider = OSP_DEF_PROVIDER;
1622         int priority_jump = 0;
1623         int cause = 0;
1624         struct varshead* headp;
1625         struct ast_var_t* current;
1626         struct osp_result result;
1627         char buffer[OSP_TOKSTR_SIZE];
1628         unsigned int callidtypes = OSP_CALLID_UNDEFINED;
1629         const char* status;
1630         char* tmp;
1631
1632         AST_DECLARE_APP_ARGS(args,
1633                 AST_APP_ARG(cause);
1634                 AST_APP_ARG(provider);
1635                 AST_APP_ARG(options);
1636         );
1637
1638         if (ast_strlen_zero(data)) {
1639                 ast_log(LOG_WARNING, "OSPNext: Arg required, OSPNext(cause[|provider[|options]])\n");
1640                 return -1;
1641         }
1642
1643         u = ast_module_user_add(chan);
1644
1645         if (!(tmp = ast_strdupa(data))) {
1646                 ast_log(LOG_ERROR, "Out of memory\n");
1647                 ast_module_user_remove(u);
1648                 return -1;
1649         }
1650
1651         AST_STANDARD_APP_ARGS(args, tmp);
1652
1653         if (!ast_strlen_zero(args.cause) && sscanf(args.cause, "%d", &cause) != 1) {
1654                 cause = 0;
1655         }
1656         if (option_debug)
1657                 ast_log(LOG_DEBUG, "OSPNext: cause '%d'\n", cause);
1658
1659         if (!ast_strlen_zero(args.provider)) {
1660                 provider = args.provider;
1661         }
1662         if (option_debug)
1663                 ast_log(LOG_DEBUG, "OSPlookup: provider '%s'\n", provider);
1664
1665         if ((args.options) && (strchr(args.options, 'j'))) {
1666                 priority_jump = 1;
1667         }
1668         if (option_debug)
1669                 ast_log(LOG_DEBUG, "OSPNext: priority jump '%d'\n", priority_jump);
1670
1671         result.inhandle = OSP_INVALID_HANDLE;
1672         result.outhandle = OSP_INVALID_HANDLE;
1673         result.intimelimit = OSP_DEF_TIMELIMIT;
1674         result.numresults = 0;
1675
1676         headp = &chan->varshead;
1677         AST_LIST_TRAVERSE(headp, current, entries) {
1678                 if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
1679                         if (sscanf(ast_var_value(current), "%d", &result.inhandle) != 1) {
1680                                 result.inhandle = OSP_INVALID_HANDLE;
1681                         }
1682                 } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
1683                         if (sscanf(ast_var_value(current), "%d", &result.outhandle) != 1) {
1684                                 result.outhandle = OSP_INVALID_HANDLE;
1685                         }
1686                 } else if (!strcasecmp(ast_var_name(current), "OSPINTIMELIMIT")) {
1687                         if (sscanf(ast_var_value(current), "%d", &result.intimelimit) != 1) {
1688                                 result.intimelimit = OSP_DEF_TIMELIMIT;
1689                         }
1690                 } else if (!strcasecmp(ast_var_name(current), "OSPOUTCALLIDTYPES")) {
1691                         if (sscanf(ast_var_value(current), "%d", &callidtypes) != 1) {
1692                                 callidtypes = OSP_CALLID_UNDEFINED;
1693                         }
1694                 } else if (!strcasecmp(ast_var_name(current), "OSPRESULTS")) {
1695                         if (sscanf(ast_var_value(current), "%d", &result.numresults) != 1) {
1696                                 result.numresults = 0;
1697                         }
1698                 }
1699         }
1700         if (option_debug) {
1701                 ast_log(LOG_DEBUG, "OSPNext: OSPINHANDLE '%d'\n", result.inhandle);
1702                 ast_log(LOG_DEBUG, "OSPNext: OSPOUTHANDLE '%d'\n", result.outhandle);
1703                 ast_log(LOG_DEBUG, "OSPNext: OSPINTIMELIMIT '%d'\n", result.intimelimit);
1704                 ast_log(LOG_DEBUG, "OSPNext: OSPOUTCALLIDTYPES '%d'\n", callidtypes);
1705                 ast_log(LOG_DEBUG, "OSPNext: OSPRESULTS '%d'\n", result.numresults);
1706         }
1707
1708         if ((res = osp_next(provider, cause, &result)) > 0) {
1709                 status = AST_OSP_SUCCESS;
1710         } else {
1711                 result.tech[0] = '\0';
1712                 result.dest[0] = '\0';
1713                 result.called[0] = '\0';
1714                 result.calling[0] = '\0';
1715                 result.token[0] = '\0';
1716                 result.networkid[0] = '\0';
1717                 result.numresults = 0;
1718                 result.outtimelimit = OSP_DEF_TIMELIMIT;
1719                 result.outcallid.buf[0] = '\0';
1720                 result.outcallid.len = 0;
1721                 if (!res) {
1722                         status = AST_OSP_FAILED;
1723                 } else {
1724                         status = AST_OSP_ERROR;
1725                 }
1726         }
1727
1728         pbx_builtin_setvar_helper(chan, "OSPTECH", result.tech);
1729         if (option_debug)
1730                 ast_log(LOG_DEBUG, "OSPNext: OSPTECH '%s'\n", result.tech);
1731         pbx_builtin_setvar_helper(chan, "OSPDEST", result.dest);
1732         if (option_debug)
1733                 ast_log(LOG_DEBUG, "OSPNext: OSPDEST '%s'\n", result.dest);
1734         pbx_builtin_setvar_helper(chan, "OSPCALLED", result.called);
1735         if (option_debug)
1736                 ast_log(LOG_DEBUG, "OSPNext: OSPCALLED'%s'\n", result.called);
1737         pbx_builtin_setvar_helper(chan, "OSPCALLING", result.calling);
1738         if (option_debug)
1739                 ast_log(LOG_DEBUG, "OSPNext: OSPCALLING '%s'\n", result.calling);
1740         pbx_builtin_setvar_helper(chan, "OSPOUTTOKEN", result.token);
1741         if (option_debug)
1742                 ast_log(LOG_DEBUG, "OSPNext: OSPOUTTOKEN size '%zd'\n", strlen(result.token));
1743         snprintf(buffer, sizeof(buffer), "%d", result.numresults);
1744         pbx_builtin_setvar_helper(chan, "OSPRESULTS", buffer);
1745         if (option_debug)
1746                 ast_log(LOG_DEBUG, "OSPNext: OSPRESULTS '%s'\n", buffer);
1747         snprintf(buffer, sizeof(buffer), "%d", result.outtimelimit);
1748         pbx_builtin_setvar_helper(chan, "OSPOUTTIMELIMIT", buffer);
1749         if (option_debug)
1750                 ast_log(LOG_DEBUG, "OSPNext: OSPOUTTIMELIMIT '%s'\n", buffer);
1751         pbx_builtin_setvar_helper(chan, "OSPNEXTSTATUS", status);
1752         if (option_debug)
1753                 ast_log(LOG_DEBUG, "OSPNext: %s\n", status);
1754
1755         if (!strcasecmp(result.tech, OSP_TECH_H323)) {
1756                 if ((callidtypes & OSP_CALLID_H323) && (result.outcallid.len != 0)) {
1757                         osp_uuid2str(result.outcallid.buf, buffer, sizeof(buffer));
1758                 } else {
1759                         buffer[0] = '\0';
1760                 }
1761                 pbx_builtin_setvar_helper(chan, "OSPOUTCALLID", buffer);
1762                 snprintf(buffer, sizeof(buffer), "%s/%s@%s", result.tech, result.called, result.dest);
1763                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
1764         } else if (!strcasecmp(result.tech, OSP_TECH_SIP)) {
1765                 snprintf(buffer, sizeof(buffer), "%s/%s@%s", result.tech, result.called, result.dest);
1766                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
1767                 if (!ast_strlen_zero(result.token)) {
1768                         snprintf(buffer, sizeof(buffer), "%s%s", OSP_SIP_HEADER, result.token);
1769                         pbx_builtin_setvar_helper(chan, "_SIPADDHEADER", buffer);
1770                         if (option_debug)
1771                                 ast_log(LOG_DEBUG, "OSPLookup: SIPADDHEADER size '%zd'\n", strlen(buffer));
1772                 }
1773         } else if (!strcasecmp(result.tech, OSP_TECH_IAX)) {
1774                 snprintf(buffer, sizeof(buffer), "%s/%s/%s", result.tech, result.dest, result.called);
1775                 pbx_builtin_setvar_helper(chan, "OSPDIALSTR", buffer);
1776         }
1777
1778         if(res <= 0) {
1779                 if (priority_jump || ast_opt_priority_jumping) {
1780                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
1781                         res = 0;
1782                 } else {
1783                         res = -1;
1784                 }
1785         } else {
1786                 res = 0;
1787         }
1788
1789         ast_module_user_remove(u);
1790
1791         return res;
1792 }
1793
1794 /*!
1795  * \brief OSP Application OSPFinish
1796  * \param chan Channel
1797  * \param data Parameter
1798  * \return 0 Success, -1 Failed
1799  */
1800 static int ospfinished_exec(
1801         struct ast_channel* chan,
1802         void* data)
1803 {
1804         int res = 1;
1805         struct ast_module_user* u;
1806         int priority_jump = 0;
1807         int cause = 0;
1808         struct varshead* headp;
1809         struct ast_var_t* current;
1810         int inhandle = OSP_INVALID_HANDLE;
1811         int outhandle = OSP_INVALID_HANDLE;
1812         int recorded = 0;
1813         time_t start, connect, end;
1814         unsigned int release;
1815         char buffer[OSP_INTSTR_SIZE];
1816         const char* status;
1817         char* tmp;
1818
1819         AST_DECLARE_APP_ARGS(args,
1820                 AST_APP_ARG(cause);
1821                 AST_APP_ARG(options);
1822         );
1823
1824         u = ast_module_user_add(chan);
1825
1826         if (!(tmp = ast_strdupa(data))) {
1827                 ast_log(LOG_ERROR, "Out of memory\n");
1828                 ast_module_user_remove(u);
1829                 return -1;
1830         }
1831
1832         AST_STANDARD_APP_ARGS(args, tmp);
1833
1834         if ((args.options) && (strchr(args.options, 'j'))) {
1835                 priority_jump = 1;
1836         }
1837         if (option_debug)
1838                 ast_log(LOG_DEBUG, "OSPFinish: priority jump '%d'\n", priority_jump);
1839
1840         headp = &chan->varshead;
1841         AST_LIST_TRAVERSE(headp, current, entries) {
1842                 if (!strcasecmp(ast_var_name(current), "OSPINHANDLE")) {
1843                         if (sscanf(ast_var_value(current), "%d", &inhandle) != 1) {
1844                                 inhandle = OSP_INVALID_HANDLE;
1845                         }
1846                 } else if (!strcasecmp(ast_var_name(current), "OSPOUTHANDLE")) {
1847                         if (sscanf(ast_var_value(current), "%d", &outhandle) != 1) {
1848                                 outhandle = OSP_INVALID_HANDLE;
1849                         }
1850                 } else if (!recorded &&
1851                         (!strcasecmp(ast_var_name(current), "OSPAUTHSTATUS") ||
1852                         !strcasecmp(ast_var_name(current), "OSPLOOKUPSTATUS") ||
1853                         !strcasecmp(ast_var_name(current), "OSPNEXTSTATUS")))
1854                 {
1855                         if (strcasecmp(ast_var_value(current), AST_OSP_SUCCESS)) {
1856                                 recorded = 1;
1857                         }
1858                 }
1859         }
1860         if (option_debug) {
1861                 ast_log(LOG_DEBUG, "OSPFinish: OSPINHANDLE '%d'\n", inhandle);
1862                 ast_log(LOG_DEBUG, "OSPFinish: OSPOUTHANDLE '%d'\n", outhandle);
1863                 ast_log(LOG_DEBUG, "OSPFinish: recorded '%d'\n", recorded);
1864         }
1865
1866         if (!ast_strlen_zero(args.cause) && sscanf(args.cause, "%d", &cause) != 1) {
1867                 cause = 0;
1868         }
1869         if (option_debug)
1870                 ast_log(LOG_DEBUG, "OSPFinish: cause '%d'\n", cause);
1871
1872         if (chan->cdr) {
1873                 start = chan->cdr->start.tv_sec;
1874                 connect = chan->cdr->answer.tv_sec;
1875                 if (connect) {
1876                         end = time(NULL);
1877                 } else {
1878                         end = connect;
1879                 }
1880         } else {
1881                 start = 0;
1882                 connect = 0;
1883                 end = 0;
1884         }
1885         if (option_debug) {
1886                 ast_log(LOG_DEBUG, "OSPFinish: start '%ld'\n", start);
1887                 ast_log(LOG_DEBUG, "OSPFinish: connect '%ld'\n", connect);
1888                 ast_log(LOG_DEBUG, "OSPFinish: end '%ld'\n", end);
1889         }
1890
1891         release = chan->_softhangup ? 0 : 1;
1892
1893         if (osp_finish(outhandle, recorded, cause, start, connect, end, release) <= 0) {
1894                 if (option_debug)
1895                         ast_log(LOG_DEBUG, "OSPFinish: Unable to report usage for outbound call\n");
1896         }
1897         switch (cause) {
1898                 case AST_CAUSE_NORMAL_CLEARING:
1899                         break;
1900                 default:
1901                         cause = AST_CAUSE_NO_ROUTE_DESTINATION;
1902                         break;
1903         }
1904         if (osp_finish(inhandle, recorded, cause, start, connect, end, release) <= 0) {
1905                 if (option_debug)
1906                         ast_log(LOG_DEBUG, "OSPFinish: Unable to report usage for inbound call\n");
1907         }
1908         snprintf(buffer, sizeof(buffer), "%d", OSP_INVALID_HANDLE);
1909         pbx_builtin_setvar_helper(chan, "OSPOUTHANDLE", buffer);
1910         pbx_builtin_setvar_helper(chan, "OSPINHANDLE", buffer);
1911
1912         if (res > 0) {
1913                 status = AST_OSP_SUCCESS;
1914         } else if (!res) {
1915                 status = AST_OSP_FAILED;
1916         } else {
1917                 status = AST_OSP_ERROR;
1918         }
1919         pbx_builtin_setvar_helper(chan, "OSPFINISHSTATUS", status);
1920
1921         if(!res) {
1922                 if (priority_jump || ast_opt_priority_jumping) {
1923                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
1924                         res = 0;
1925                 } else {
1926                         res = -1;
1927                 }
1928         } else {
1929                 res = 0;
1930         }
1931
1932         ast_module_user_remove(u);
1933
1934         return res;
1935 }
1936
1937 /* OSP Module APIs */
1938
1939 static int osp_load(void)
1940 {
1941         const char* t;
1942         unsigned int v;
1943         struct ast_config* cfg;
1944         int error = OSPC_ERR_NO_ERROR;
1945
1946         cfg = ast_config_load(OSP_CONFIG_FILE);
1947         if (cfg) {
1948                 t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "accelerate");
1949                 if (t && ast_true(t)) {
1950                         if ((error = OSPPInit(1)) != OSPC_ERR_NO_ERROR) {
1951                                 ast_log(LOG_WARNING, "OSP: Unable to enable hardware accelleration\n");
1952                                 OSPPInit(0);
1953                         } else {
1954                                 osp_hardware = 1;
1955                         }
1956                 } else {
1957                         OSPPInit(0);
1958                 }
1959                 if (option_debug)
1960                         ast_log(LOG_DEBUG, "OSP: osp_hardware '%d'\n", osp_hardware);
1961
1962                 t = ast_variable_retrieve(cfg, OSP_GENERAL_CAT, "tokenformat");
1963                 if (t) {
1964                         if ((sscanf(t, "%d", &v) == 1) &&
1965                                 ((v == TOKEN_ALGO_SIGNED) || (v == TOKEN_ALGO_UNSIGNED) || (v == TOKEN_ALGO_BOTH)))
1966                         {
1967                                 osp_tokenformat = v;
1968                         } else {
1969                                 ast_log(LOG_WARNING, "tokenformat should be an integer from %d, %d or %d, not '%s'\n",
1970                                         TOKEN_ALGO_SIGNED, TOKEN_ALGO_UNSIGNED, TOKEN_ALGO_BOTH, t);
1971                         }
1972                 }
1973                 if (option_debug)
1974                         ast_log(LOG_DEBUG, "OSP: osp_tokenformat '%d'\n", osp_tokenformat);
1975
1976                 t = ast_category_browse(cfg, NULL);
1977                 while(t) {
1978                         if (strcasecmp(t, OSP_GENERAL_CAT)) {
1979                                 osp_create_provider(cfg, t);
1980                         }
1981                         t = ast_category_browse(cfg, t);
1982                 }
1983
1984                 osp_initialized = 1;
1985
1986                 ast_config_destroy(cfg);
1987         } else {
1988                 ast_log(LOG_WARNING, "OSP: Unable to find configuration. OSP support disabled\n");
1989                 return 0;
1990         }
1991         if (option_debug)
1992                 ast_log(LOG_DEBUG, "OSP: osp_initialized '%d'\n", osp_initialized);
1993
1994         return 1;
1995 }
1996
1997 static int osp_unload(void)
1998 {
1999         struct osp_provider* p;
2000         struct osp_provider* next;
2001
2002         if (osp_initialized) {
2003                 ast_mutex_lock(&osplock);
2004                 p = ospproviders;
2005                 while(p) {
2006                         next = p->next;
2007                         OSPPProviderDelete(p->handle, 0);
2008                         free(p);
2009                         p = next;
2010                 }
2011                 ospproviders = NULL;
2012                 ast_mutex_unlock(&osplock);
2013
2014                 OSPPCleanup();
2015
2016                 osp_tokenformat = TOKEN_ALGO_SIGNED;
2017                 osp_hardware = 0;
2018                 osp_initialized = 0;
2019         }
2020         return 0;
2021 }
2022
2023 static int osp_show(
2024         int fd,
2025         int argc,
2026         char* argv[])
2027 {
2028         int i;
2029         int found = 0;
2030         struct osp_provider* p;
2031         const char* provider = NULL;
2032         const char* tokenalgo;
2033
2034         if ((argc < 2) || (argc > 3)) {
2035                 return RESULT_SHOWUSAGE;
2036         }
2037         if (argc > 2) {
2038                 provider = argv[2];
2039         }
2040         if (!provider) {
2041                 switch (osp_tokenformat) {
2042                         case TOKEN_ALGO_BOTH:
2043                                 tokenalgo = "Both";
2044                                 break;
2045                         case TOKEN_ALGO_UNSIGNED:
2046                                 tokenalgo = "Unsigned";
2047                                 break;
2048                         case TOKEN_ALGO_SIGNED:
2049                         default:
2050                                 tokenalgo = "Signed";
2051                                 break;
2052                 }
2053                 ast_cli(fd, "OSP: %s %s %s\n",
2054                         osp_initialized ? "Initialized" : "Uninitialized", osp_hardware ? "Accelerated" : "Normal", tokenalgo);
2055         }
2056
2057         ast_mutex_lock(&osplock);
2058         p = ospproviders;
2059         while(p) {
2060                 if (!provider || !strcasecmp(p->name, provider)) {
2061                         if (found) {
2062                                 ast_cli(fd, "\n");
2063                         }
2064                         ast_cli(fd, " == OSP Provider '%s' == \n", p->name);
2065                         ast_cli(fd, "Local Private Key: %s\n", p->privatekey);
2066                         ast_cli(fd, "Local Certificate: %s\n", p->localcert);
2067                         for (i = 0; i < p->cacount; i++) {
2068                                 ast_cli(fd, "CA Certificate %d:  %s\n", i + 1, p->cacerts[i]);
2069                         }
2070                         for (i = 0; i < p->spcount; i++) {
2071                                 ast_cli(fd, "Service Point %d:   %s\n", i + 1, p->srvpoints[i]);
2072                         }
2073                         ast_cli(fd, "Max Connections:   %d\n", p->maxconnections);
2074                         ast_cli(fd, "Retry Delay:       %d seconds\n", p->retrydelay);
2075                         ast_cli(fd, "Retry Limit:       %d\n", p->retrylimit);
2076                         ast_cli(fd, "Timeout:           %d milliseconds\n", p->timeout);
2077                         ast_cli(fd, "Source:            %s\n", strlen(p->source) ? p->source : "<unspecified>");
2078                         ast_cli(fd, "Auth Policy        %d\n", p->authpolicy);
2079                         ast_cli(fd, "Default protocol   %s\n", p->defaultprotocol);
2080                         ast_cli(fd, "OSP Handle:        %d\n", p->handle);
2081                         found++;
2082                 }
2083                 p = p->next;
2084         }
2085         ast_mutex_unlock(&osplock);
2086
2087         if (!found) {
2088                 if (provider) {
2089                         ast_cli(fd, "Unable to find OSP provider '%s'\n", provider);
2090                 } else {
2091                         ast_cli(fd, "No OSP providers configured\n");
2092                 }
2093         }
2094         return RESULT_SUCCESS;
2095 }
2096
2097 static const char* app1= "OSPAuth";
2098 static const char* synopsis1 = "OSP authentication";
2099 static const char* descrip1 =
2100 "  OSPAuth([provider[|options]]):  Authenticate a SIP INVITE by OSP and sets\n"
2101 "the variables:\n"
2102 " ${OSPINHANDLE}:  The inbound call transaction handle\n"
2103 " ${OSPINTIMELIMIT}:  The inbound call duration limit in seconds\n"
2104 "\n"
2105 "The option string may contain the following character:\n"
2106 "       'j' -- jump to n+101 priority if the authentication was NOT successful\n"
2107 "This application sets the following channel variable upon completion:\n"
2108 "       OSPAUTHSTATUS   The status of the OSP Auth attempt as a text string, one of\n"
2109 "               SUCCESS | FAILED | ERROR\n";
2110
2111 static const char* app2= "OSPLookup";
2112 static const char* synopsis2 = "Lookup destination by OSP";
2113 static const char* descrip2 =
2114 "  OSPLookup(exten[|provider[|options]]):  Looks up an extension via OSP and sets\n"
2115 "the variables, where 'n' is the number of the result beginning with 1:\n"
2116 " ${OSPOUTHANDLE}:  The OSP Handle for anything remaining\n"
2117 " ${OSPTECH}:  The technology to use for the call\n"
2118 " ${OSPDEST}:  The destination to use for the call\n"
2119 " ${OSPCALLED}:  The called number to use for the call\n"
2120 " ${OSPCALLING}:  The calling number to use for the call\n"
2121 " ${OSPDIALSTR}:  The dial command string\n"
2122 " ${OSPOUTTOKEN}:  The actual OSP token as a string\n"
2123 " ${OSPOUTTIMELIMIT}:  The outbound call duration limit in seconds\n"
2124 " ${OSPOUTCALLIDTYPES}:  The outbound call id types\n"
2125 " ${OSPOUTCALLID}:  The outbound call id\n"
2126 " ${OSPRESULTS}:  The number of OSP results total remaining\n"
2127 "\n"
2128 "The option string may contain the following character:\n"
2129 "       'j' -- jump to n+101 priority if the lookup was NOT successful\n"
2130 "       'h' -- generate H323 call id for the outbound call\n"
2131 "       's' -- generate SIP call id for the outbound call. Have not been implemented\n"
2132 "       'i' -- generate IAX call id for the outbound call. Have not been implemented\n"
2133 "This application sets the following channel variable upon completion:\n"
2134 "       OSPLOOKUPSTATUS The status of the OSP Lookup attempt as a text string, one of\n"
2135 "               SUCCESS | FAILED | ERROR\n";
2136
2137 static const char* app3 = "OSPNext";
2138 static const char* synopsis3 = "Lookup next destination by OSP";
2139 static const char* descrip3 =
2140 "  OSPNext(cause[|provider[|options]]):  Looks up the next OSP Destination for ${OSPOUTHANDLE}\n"
2141 "See OSPLookup for more information\n"
2142 "\n"
2143 "The option string may contain the following character:\n"
2144 "       'j' -- jump to n+101 priority if the lookup was NOT successful\n"
2145 "This application sets the following channel variable upon completion:\n"
2146 "       OSPNEXTSTATUS The status of the OSP Next attempt as a text string, one of\n"
2147 "               SUCCESS | FAILED | ERROR\n";
2148
2149 static const char* app4 = "OSPFinish";
2150 static const char* synopsis4 = "Record OSP entry";
2151 static const char* descrip4 =
2152 "  OSPFinish([status[|options]]):  Records call state for ${OSPINHANDLE}, according to\n"
2153 "status, which should be one of BUSY, CONGESTION, ANSWER, NOANSWER, or CHANUNAVAIL\n"
2154 "or coincidentally, just what the Dial application stores in its ${DIALSTATUS}.\n"
2155 "\n"
2156 "The option string may contain the following character:\n"
2157 "       'j' -- jump to n+101 priority if the finish attempt was NOT successful\n"
2158 "This application sets the following channel variable upon completion:\n"
2159 "       OSPFINISHSTATUS The status of the OSP Finish attempt as a text string, one of\n"
2160 "               SUCCESS | FAILED | ERROR \n";
2161
2162 static const char osp_usage[] =
2163 "Usage: osp show\n"
2164 "       Displays information on Open Settlement Protocol support\n";
2165
2166 static struct ast_cli_entry cli_osp[] = {
2167         { {"osp", "show", NULL},
2168         osp_show, "Displays OSP information",
2169         osp_usage },
2170 };
2171
2172 static int load_module(void)
2173 {
2174         int res;
2175
2176         if(!osp_load())
2177                 return AST_MODULE_LOAD_DECLINE;
2178
2179         ast_cli_register_multiple(cli_osp, sizeof(cli_osp) / sizeof(struct ast_cli_entry));
2180         res = ast_register_application(app1, ospauth_exec, synopsis1, descrip1);
2181         res |= ast_register_application(app2, osplookup_exec, synopsis2, descrip2);
2182         res |= ast_register_application(app3, ospnext_exec, synopsis3, descrip3);
2183         res |= ast_register_application(app4, ospfinished_exec, synopsis4, descrip4);
2184
2185         return res;
2186 }
2187
2188 static int unload_module(void)
2189 {
2190         int res;
2191
2192         res = ast_unregister_application(app4);
2193         res |= ast_unregister_application(app3);
2194         res |= ast_unregister_application(app2);
2195         res |= ast_unregister_application(app1);
2196         ast_cli_unregister_multiple(cli_osp, sizeof(cli_osp) / sizeof(struct ast_cli_entry));
2197         osp_unload();
2198
2199         ast_module_user_hangup_all();
2200
2201         return res;
2202 }
2203
2204 static int reload(void)
2205 {
2206         osp_unload();
2207         osp_load();
2208
2209         return 0;
2210 }
2211
2212 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Open Settlement Protocol Applications",
2213         .load = load_module,
2214         .unload = unload_module,
2215         .reload = reload,
2216         );