Sat Nov 1 06:28:20 2008

Asterisk developer's documentation


app_osplookup.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*!
00020  * \file
00021  * \brief Open Settlement Protocol (OSP) Applications
00022  *
00023  * \author Mark Spencer <markster@digium.com>
00024  * 
00025  * \ingroup applications
00026  */
00027 
00028 /*** MODULEINFO
00029    <depend>osptk</depend>
00030    <depend>ssl</depend>
00031  ***/
00032 
00033 #include "asterisk.h"
00034 
00035 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 86438 $")
00036 
00037 #include <sys/types.h>
00038 #include <stdio.h>
00039 #include <string.h>
00040 #include <unistd.h>
00041 #include <errno.h>
00042 #include <osp/osp.h>
00043 #include <osp/osputils.h>
00044 
00045 #include "asterisk/lock.h"
00046 #include "asterisk/config.h"
00047 #include "asterisk/utils.h"
00048 #include "asterisk/causes.h"
00049 #include "asterisk/channel.h"
00050 #include "asterisk/app.h"
00051 #include "asterisk/module.h"
00052 #include "asterisk/pbx.h"
00053 #include "asterisk/options.h"
00054 #include "asterisk/cli.h"
00055 #include "asterisk/logger.h"
00056 #include "asterisk/astosp.h"
00057 
00058 /* OSP Buffer Sizes */
00059 #define OSP_INTSTR_SIZE       ((unsigned int)16)         /* OSP signed/unsigned int string buffer size */
00060 #define OSP_NORSTR_SIZE       ((unsigned int)256)        /* OSP normal string buffer size */
00061 #define OSP_TOKSTR_SIZE       ((unsigned int)4096)       /* OSP token string buffer size */
00062 
00063 /* OSP Constants */
00064 #define OSP_INVALID_HANDLE    ((int)-1)            /* Invalid OSP handle, provider, transaction etc. */
00065 #define OSP_CONFIG_FILE       ((const char*)"osp.conf")     /* OSP configuration file name */
00066 #define OSP_GENERAL_CAT       ((const char*)"general")      /* OSP global configuration context name */
00067 #define OSP_DEF_PROVIDER      ((const char*)"default")      /* OSP default provider context name */
00068 #define OSP_MAX_CERTS         ((unsigned int)10)         /* OSP max number of cacerts */
00069 #define OSP_MAX_SRVS       ((unsigned int)10)         /* OSP max number of service points */
00070 #define OSP_DEF_MAXCONNECTIONS      ((unsigned int)20)         /* OSP default max_connections */
00071 #define OSP_MIN_MAXCONNECTIONS      ((unsigned int)1)       /* OSP min max_connections */
00072 #define OSP_MAX_MAXCONNECTIONS      ((unsigned int)1000)       /* OSP max max_connections */
00073 #define OSP_DEF_RETRYDELAY    ((unsigned int)0)       /* OSP default retry delay */
00074 #define OSP_MIN_RETRYDELAY    ((unsigned int)0)       /* OSP min retry delay */
00075 #define OSP_MAX_RETRYDELAY    ((unsigned int)10)         /* OSP max retry delay */
00076 #define OSP_DEF_RETRYLIMIT    ((unsigned int)2)       /* OSP default retry times */
00077 #define OSP_MIN_RETRYLIMIT    ((unsigned int)0)       /* OSP min retry times */
00078 #define OSP_MAX_RETRYLIMIT    ((unsigned int)100)        /* OSP max retry times */
00079 #define OSP_DEF_TIMEOUT       ((unsigned int)500)        /* OSP default timeout in ms */
00080 #define OSP_MIN_TIMEOUT       ((unsigned int)200)        /* OSP min timeout in ms */
00081 #define OSP_MAX_TIMEOUT       ((unsigned int)10000)         /* OSP max timeout in ms */
00082 #define OSP_DEF_AUTHPOLICY    ((enum osp_authpolicy)OSP_AUTH_YES)
00083 #define OSP_AUDIT_URL         ((const char*)"localhost")    /* OSP default Audit URL */
00084 #define OSP_LOCAL_VALIDATION     ((int)1)          /* Validate OSP token locally */
00085 #define OSP_SSL_LIFETIME      ((unsigned int)300)        /* SSL life time, in seconds */
00086 #define OSP_HTTP_PERSISTENCE     ((int)1)          /* In seconds */
00087 #define OSP_CUSTOMER_ID       ((const char*)"")       /* OSP customer ID */
00088 #define OSP_DEVICE_ID         ((const char*)"")       /* OSP device ID */
00089 #define OSP_DEF_DESTINATIONS     ((unsigned int)5)       /* OSP default max number of destinations */
00090 #define OSP_DEF_TIMELIMIT     ((unsigned int)0)       /* OSP default duration limit, no limit */
00091 
00092 /* OSP Authentication Policy */
00093 enum osp_authpolicy {
00094    OSP_AUTH_NO,      /* Accept any call */
00095    OSP_AUTH_YES,     /* Accept call with valid OSP token or without OSP token */
00096    OSP_AUTH_EXCLUSIVE   /* Only accept call with valid OSP token */
00097 };
00098 
00099 /* OSP Provider */
00100 struct osp_provider {
00101    char name[OSP_NORSTR_SIZE];            /* OSP provider context name */
00102    char privatekey[OSP_NORSTR_SIZE];         /* OSP private key file name */
00103    char localcert[OSP_NORSTR_SIZE];       /* OSP local cert file name */
00104    unsigned int cacount;               /* Number of cacerts */
00105    char cacerts[OSP_MAX_CERTS][OSP_NORSTR_SIZE];      /* Cacert file names */
00106    unsigned int spcount;               /* Number of service points */
00107    char srvpoints[OSP_MAX_SRVS][OSP_NORSTR_SIZE];     /* Service point URLs */
00108    int maxconnections;              /* Max number of connections */
00109    int retrydelay;                  /* Retry delay */
00110    int retrylimit;                  /* Retry limit */
00111    int timeout;                  /* Timeout in ms */
00112    char source[OSP_NORSTR_SIZE];          /* IP of self */
00113    enum osp_authpolicy authpolicy;           /* OSP authentication policy */
00114    OSPTPROVHANDLE handle;              /* OSP provider handle */
00115    struct osp_provider* next;          /* Pointer to next OSP provider */
00116 };
00117 
00118 /* OSP Application In/Output Results */
00119 struct osp_result {
00120    int inhandle;                 /* Inbound transaction handle */
00121    int outhandle;                /* Outbound transaction handle */
00122    unsigned int intimelimit;           /* Inbound duration limit */
00123    unsigned int outtimelimit;          /* Outbound duration limit */
00124    char tech[20];                /* Asterisk TECH string */
00125    char dest[OSP_NORSTR_SIZE];            /* Destination in called@IP format */
00126    char calling[OSP_NORSTR_SIZE];            /* Calling number, may be translated */
00127    char token[OSP_TOKSTR_SIZE];           /* Outbound OSP token */
00128    unsigned int numresults;            /* Number of remain destinations */
00129 };
00130 
00131 /* OSP Module Global Variables */
00132 AST_MUTEX_DEFINE_STATIC(osplock);            /* Lock of OSP provider list */
00133 static int osp_initialized = 0;              /* Init flag */
00134 static int osp_hardware = 0;              /* Hardware accelleration flag */
00135 static struct osp_provider* ospproviders = NULL;      /* OSP provider list */
00136 static unsigned int osp_tokenformat = TOKEN_ALGO_SIGNED; /* Token format supported */
00137 
00138 /* OSP Client Wrapper APIs */
00139 
00140 /*!
00141  * \brief Create OSP provider handle according to configuration
00142  * \param cfg OSP configuration
00143  * \param provider OSP provider context name
00144  * \return 1 Success, 0 Failed, -1 Error
00145  */
00146 static int osp_create_provider(struct ast_config* cfg, const char* provider)
00147 {
00148    int res;
00149    unsigned int t, i, j;
00150    struct osp_provider* p;
00151    struct ast_variable* v;
00152    OSPTPRIVATEKEY privatekey;
00153    OSPTCERT localcert;
00154    const char* psrvpoints[OSP_MAX_SRVS];
00155    OSPTCERT cacerts[OSP_MAX_CERTS];
00156    const OSPTCERT* pcacerts[OSP_MAX_CERTS];
00157    int error = OSPC_ERR_NO_ERROR;
00158 
00159    if (!(p = ast_calloc(1, sizeof(*p)))) {
00160       ast_log(LOG_ERROR, "Out of memory\n");
00161       return -1;
00162    }
00163 
00164    ast_copy_string(p->name, provider, sizeof(p->name));
00165    snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s-privatekey.pem", ast_config_AST_KEY_DIR, provider);
00166    snprintf(p->localcert, sizeof(p->localcert), "%s/%s-localcert.pem", ast_config_AST_KEY_DIR, provider);
00167    p->maxconnections = OSP_DEF_MAXCONNECTIONS;
00168    p->retrydelay = OSP_DEF_RETRYDELAY;
00169    p->retrylimit = OSP_DEF_RETRYLIMIT;
00170    p->timeout = OSP_DEF_TIMEOUT;
00171    p->authpolicy = OSP_DEF_AUTHPOLICY;
00172    p->handle = OSP_INVALID_HANDLE;
00173 
00174    v = ast_variable_browse(cfg, provider);
00175    while(v) {
00176       if (!strcasecmp(v->name, "privatekey")) {
00177          if (v->value[0] == '/') {
00178             ast_copy_string(p->privatekey, v->value, sizeof(p->privatekey));
00179          } else {
00180             snprintf(p->privatekey, sizeof(p->privatekey), "%s/%s", ast_config_AST_KEY_DIR, v->value);
00181          }
00182          ast_log(LOG_DEBUG, "OSP: privatekey '%s'\n", p->privatekey);
00183       } else if (!strcasecmp(v->name, "localcert")) {
00184          if (v->value[0] == '/') {
00185             ast_copy_string(p->localcert, v->value, sizeof(p->localcert));
00186          } else {
00187             snprintf(p->localcert, sizeof(p->localcert), "%s/%s", ast_config_AST_KEY_DIR, v->value);
00188          }
00189          ast_log(LOG_DEBUG, "OSP: localcert '%s'\n", p->localcert);
00190       } else if (!strcasecmp(v->name, "cacert")) {
00191          if (p->cacount < OSP_MAX_CERTS) {
00192             if (v->value[0] == '/') {
00193                ast_copy_string(p->cacerts[p->cacount], v->value, sizeof(p->cacerts[0]));
00194             } else {
00195                snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s", ast_config_AST_KEY_DIR, v->value);
00196             }
00197             ast_log(LOG_DEBUG, "OSP: cacert[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]);
00198             p->cacount++;
00199          } else {
00200             ast_log(LOG_WARNING, "OSP: Too many CA Certificates at line %d\n", v->lineno);
00201          }
00202       } else if (!strcasecmp(v->name, "servicepoint")) {
00203          if (p->spcount < OSP_MAX_SRVS) {
00204             ast_copy_string(p->srvpoints[p->spcount], v->value, sizeof(p->srvpoints[0]));
00205             ast_log(LOG_DEBUG, "OSP: servicepoint[%d]: '%s'\n", p->spcount, p->srvpoints[p->spcount]);
00206             p->spcount++;
00207          } else {
00208             ast_log(LOG_WARNING, "OSP: Too many Service Points at line %d\n", v->lineno);
00209          }
00210       } else if (!strcasecmp(v->name, "maxconnections")) {
00211          if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_MAXCONNECTIONS) && (t <= OSP_MAX_MAXCONNECTIONS)) {
00212             p->maxconnections = t;
00213             ast_log(LOG_DEBUG, "OSP: maxconnections '%d'\n", t);
00214          } else {
00215             ast_log(LOG_WARNING, "OSP: maxconnections should be an integer from %d to %d, not '%s' at line %d\n", 
00216                OSP_MIN_MAXCONNECTIONS, OSP_MAX_MAXCONNECTIONS, v->value, v->lineno);
00217          }
00218       } else if (!strcasecmp(v->name, "retrydelay")) {
00219          if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_RETRYDELAY) && (t <= OSP_MAX_RETRYDELAY)) {
00220             p->retrydelay = t;
00221             ast_log(LOG_DEBUG, "OSP: retrydelay '%d'\n", t);
00222          } else {
00223             ast_log(LOG_WARNING, "OSP: retrydelay should be an integer from %d to %d, not '%s' at line %d\n", 
00224                OSP_MIN_RETRYDELAY, OSP_MAX_RETRYDELAY, v->value, v->lineno);
00225          }
00226       } else if (!strcasecmp(v->name, "retrylimit")) {
00227          if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_RETRYLIMIT) && (t <= OSP_MAX_RETRYLIMIT)) {
00228             p->retrylimit = t;
00229             ast_log(LOG_DEBUG, "OSP: retrylimit '%d'\n", t);
00230          } else {
00231             ast_log(LOG_WARNING, "OSP: retrylimit should be an integer from %d to %d, not '%s' at line %d\n", 
00232                OSP_MIN_RETRYLIMIT, OSP_MAX_RETRYLIMIT, v->value, v->lineno);
00233          }
00234       } else if (!strcasecmp(v->name, "timeout")) {
00235          if ((sscanf(v->value, "%d", &t) == 1) && (t >= OSP_MIN_TIMEOUT) && (t <= OSP_MAX_TIMEOUT)) {
00236             p->timeout = t;
00237             ast_log(LOG_DEBUG, "OSP: timeout '%d'\n", t);
00238          } else {
00239             ast_log(LOG_WARNING, "OSP: timeout should be an integer from %d to %d, not '%s' at line %d\n", 
00240                OSP_MIN_TIMEOUT, OSP_MAX_TIMEOUT, v->value, v->lineno);
00241          }
00242       } else if (!strcasecmp(v->name, "source")) {
00243          ast_copy_string(p->source, v->value, sizeof(p->source));
00244          ast_log(LOG_DEBUG, "OSP: source '%s'\n", p->source);
00245       } else if (!strcasecmp(v->name, "authpolicy")) {
00246          if ((sscanf(v->value, "%d", &t) == 1) && ((t == OSP_AUTH_NO) || (t == OSP_AUTH_YES) || (t == OSP_AUTH_EXCLUSIVE))) {
00247             p->authpolicy = t;
00248             ast_log(LOG_DEBUG, "OSP: authpolicy '%d'\n", t);
00249          } else {
00250             ast_log(LOG_WARNING, "OSP: authpolicy should be %d, %d or %d, not '%s' at line %d\n", 
00251                OSP_AUTH_NO, OSP_AUTH_YES, OSP_AUTH_EXCLUSIVE, v->value, v->lineno);
00252          }
00253       }
00254       v = v->next;
00255    }
00256 
00257    error = OSPPUtilLoadPEMPrivateKey((unsigned char *) p->privatekey, &privatekey);
00258    if (error != OSPC_ERR_NO_ERROR) {
00259       ast_log(LOG_WARNING, "OSP: Unable to load privatekey '%s', error '%d'\n", p->privatekey, error);
00260       free(p);
00261       return 0;
00262    }
00263 
00264    error = OSPPUtilLoadPEMCert((unsigned char *) p->localcert, &localcert);
00265    if (error != OSPC_ERR_NO_ERROR) {
00266       ast_log(LOG_WARNING, "OSP: Unable to load localcert '%s', error '%d'\n", p->localcert, error);
00267       if (privatekey.PrivateKeyData) {
00268          free(privatekey.PrivateKeyData);
00269       }
00270       free(p);
00271       return 0;
00272    }
00273 
00274    if (p->cacount < 1) {
00275       snprintf(p->cacerts[p->cacount], sizeof(p->cacerts[0]), "%s/%s-cacert.pem", ast_config_AST_KEY_DIR, provider);
00276       ast_log(LOG_DEBUG, "OSP: cacert[%d]: '%s'\n", p->cacount, p->cacerts[p->cacount]);
00277       p->cacount++;
00278    }
00279    for (i = 0; i < p->cacount; i++) {
00280       error = OSPPUtilLoadPEMCert((unsigned char *) p->cacerts[i], &cacerts[i]);
00281       if (error != OSPC_ERR_NO_ERROR) {
00282          ast_log(LOG_WARNING, "OSP: Unable to load cacert '%s', error '%d'\n", p->cacerts[i], error);
00283          for (j = 0; j < i; j++) {
00284             if (cacerts[j].CertData) {
00285                free(cacerts[j].CertData);
00286             }
00287          }
00288          if (localcert.CertData) {
00289             free(localcert.CertData);
00290          }
00291          if (privatekey.PrivateKeyData) {
00292             free(privatekey.PrivateKeyData);
00293          }
00294          free(p);
00295          return 0;
00296       }
00297       pcacerts[i] = &cacerts[i];
00298    }
00299    
00300    for (i = 0; i < p->spcount; i++) {
00301       psrvpoints[i] = p->srvpoints[i];
00302    }
00303 
00304    error = OSPPProviderNew(p->spcount, psrvpoints, NULL, OSP_AUDIT_URL, &privatekey, &localcert, p->cacount, pcacerts, OSP_LOCAL_VALIDATION,
00305             OSP_SSL_LIFETIME, p->maxconnections, OSP_HTTP_PERSISTENCE, p->retrydelay, p->retrylimit,p->timeout, OSP_CUSTOMER_ID,
00306             OSP_DEVICE_ID, &p->handle);
00307    if (error != OSPC_ERR_NO_ERROR) {
00308       ast_log(LOG_WARNING, "OSP: Unable to create provider '%s', error '%d'\n", provider, error);
00309       free(p);
00310       res = -1;
00311    } else {
00312       ast_log(LOG_DEBUG, "OSP: provider '%s'\n", provider);
00313       ast_mutex_lock(&osplock);
00314       p->next = ospproviders;
00315       ospproviders = p;
00316       ast_mutex_unlock(&osplock);   
00317       res = 1;
00318    }
00319 
00320    for (i = 0; i < p->cacount; i++) {
00321       if (cacerts[i].CertData) {
00322          free(cacerts[i].CertData);
00323       }
00324    }
00325    if (localcert.CertData) {
00326       free(localcert.CertData);
00327    }
00328    if (privatekey.PrivateKeyData) {
00329       free(privatekey.PrivateKeyData);
00330    }
00331 
00332    return res;
00333 }
00334 
00335 /*!
00336  * \brief Get OSP authenticiation policy of provider
00337  * \param provider OSP provider context name
00338  * \param policy OSP authentication policy, output
00339  * \return 1 Success, 0 Failed, -1 Error
00340  */
00341 static int osp_get_policy(const char* provider, int* policy)
00342 {
00343    int res = 0;
00344    struct osp_provider* p;
00345 
00346    ast_mutex_lock(&osplock);
00347    p = ospproviders;
00348    while(p) {
00349       if (!strcasecmp(p->name, provider)) {
00350          *policy = p->authpolicy;
00351          ast_log(LOG_DEBUG, "OSP: authpolicy '%d'\n", *policy);
00352          res = 1;
00353          break;
00354       }
00355       p = p->next;
00356    }
00357    ast_mutex_unlock(&osplock);
00358 
00359    return res;
00360 }
00361 
00362 /*!
00363  * \brief Create OSP transaction handle
00364  * \param provider OSP provider context name
00365  * \param transaction OSP transaction handle, output
00366  * \param sourcesize Size of source buffer, in/output
00367  * \param source Source of provider, output
00368  * \return 1 Success, 0 Failed, -1 Error
00369  */
00370 static int osp_create_transaction(const char* provider, int* transaction, unsigned int sourcesize, char* source)
00371 {
00372    int res = 0;
00373    struct osp_provider* p;
00374    int error;
00375 
00376    ast_mutex_lock(&osplock);
00377    p = ospproviders;
00378    while(p) {
00379       if (!strcasecmp(p->name, provider)) {
00380          error = OSPPTransactionNew(p->handle, transaction);
00381          if (error == OSPC_ERR_NO_ERROR) {
00382             ast_log(LOG_DEBUG, "OSP: transaction '%d'\n", *transaction);
00383             ast_copy_string(source, p->source, sourcesize);
00384             ast_log(LOG_DEBUG, "OSP: source '%s'\n", source);
00385             res = 1;
00386          } else {
00387             *transaction = OSP_INVALID_HANDLE;
00388             ast_log(LOG_DEBUG, "OSP: Unable to create transaction handle, error '%d'\n", error);
00389             res = -1;
00390          }
00391          break;
00392       }
00393       p = p->next;
00394    }
00395    ast_mutex_unlock(&osplock);
00396 
00397    return res;
00398 }
00399 
00400 /*!
00401  * \brief Convert address to "[x.x.x.x]" or "host.domain" format
00402  * \param src Source address string
00403  * \param dst Destination address string
00404  * \param buffersize Size of dst buffer
00405  */
00406 static void osp_convert_address(
00407    const char* src,
00408    char* dst,
00409    int buffersize)
00410 {
00411    struct in_addr inp;
00412 
00413    if (inet_aton(src, &inp) != 0) {
00414       snprintf(dst, buffersize, "[%s]", src);
00415    } else {
00416       snprintf(dst, buffersize, "%s", src);
00417    }
00418 }
00419 
00420 /*!
00421  * \brief Validate OSP token of inbound call
00422  * \param transaction OSP transaction handle
00423  * \param source Source of inbound call
00424  * \param dest Destination of inbound call
00425  * \param calling Calling number
00426  * \param called Called number
00427  * \param token OSP token, may be empty
00428  * \param timelimit Call duration limit, output
00429  * \return 1 Success, 0 Failed, -1 Error
00430  */
00431 static int osp_validate_token(int transaction, const char* source, const char* dest, const char* calling, const char* called, const char* token, unsigned int* timelimit)
00432 {
00433    int res;
00434    int tokenlen;
00435    unsigned char tokenstr[OSP_TOKSTR_SIZE];
00436    char src[OSP_NORSTR_SIZE];
00437    char dst[OSP_NORSTR_SIZE];
00438    unsigned int authorised;
00439    unsigned int dummy = 0;
00440    int error;
00441 
00442    tokenlen = ast_base64decode(tokenstr, token, strlen(token));
00443    osp_convert_address(source, src, sizeof(src));
00444    osp_convert_address(dest, dst, sizeof(dst));
00445    error = OSPPTransactionValidateAuthorisation(
00446       transaction, 
00447       src, dst, NULL, NULL,
00448       calling ? calling : "", OSPC_E164, 
00449       called, OSPC_E164, 
00450       0, NULL,
00451       tokenlen, (char *) tokenstr, 
00452       &authorised, 
00453       timelimit, 
00454       &dummy, NULL, 
00455       osp_tokenformat); 
00456    if (error != OSPC_ERR_NO_ERROR) {
00457       ast_log(LOG_DEBUG, "OSP: Unable to validate inbound token\n");
00458       res = -1;
00459    } else if (authorised) {
00460       ast_log(LOG_DEBUG, "OSP: Authorised\n");
00461       res = 1;
00462    } else {
00463       ast_log(LOG_DEBUG, "OSP: Unauthorised\n");
00464       res = 0;
00465    }
00466    
00467    return res;
00468 }
00469 
00470 /*!
00471  * \brief Choose min duration limit
00472  * \param in Inbound duration limit
00473  * \param out Outbound duration limit
00474  * \return min duration limit
00475  */
00476 static unsigned int osp_choose_timelimit(unsigned int in, unsigned int out)
00477 {
00478    if (in == OSP_DEF_TIMELIMIT) {
00479       return out;
00480    } else if (out == OSP_DEF_TIMELIMIT) {
00481       return in;
00482    } else {
00483       return in < out ? in : out;
00484    }
00485 }
00486 
00487 /*!
00488  * \brief Choose min duration limit
00489  * \param called Called number
00490  * \param calling Calling number
00491  * \param destination Destination IP in '[x.x.x.x]' format
00492  * \param tokenlen OSP token length
00493  * \param token OSP token
00494  * \param reason Failure reason, output
00495  * \param result OSP lookup results, in/output
00496  * \return 1 Success, 0 Failed, -1 Error
00497  */
00498 static int osp_check_destination(const char* called, const char* calling, char* destination, unsigned int tokenlen, const char* token, enum OSPEFAILREASON* reason, struct osp_result* result)
00499 {
00500    int res;
00501    OSPE_DEST_OSP_ENABLED enabled;
00502    OSPE_DEST_PROT protocol;
00503    int error;
00504 
00505    if (strlen(destination) <= 2) {
00506       ast_log(LOG_DEBUG, "OSP: Wrong destination format '%s'\n", destination);
00507       *reason = OSPC_FAIL_NORMAL_UNSPECIFIED;
00508       return -1;
00509    } 
00510 
00511    if ((error = OSPPTransactionIsDestOSPEnabled(result->outhandle, &enabled)) != OSPC_ERR_NO_ERROR) {
00512       ast_log(LOG_DEBUG, "OSP: Unable to get destination OSP version, error '%d'\n", error);
00513       *reason = OSPC_FAIL_NORMAL_UNSPECIFIED;
00514       return -1;
00515    }
00516 
00517    if (enabled == OSPE_OSP_FALSE) {
00518       result->token[0] = '\0';
00519    } else {
00520       ast_base64encode(result->token, (const unsigned char *) token, tokenlen, sizeof(result->token) - 1);
00521    }
00522 
00523    if ((error = OSPPTransactionGetDestProtocol(result->outhandle, &protocol)) != OSPC_ERR_NO_ERROR) {
00524       ast_log(LOG_DEBUG, "OSP: Unable to get destination protocol, error '%d'\n", error);
00525       *reason = OSPC_FAIL_NORMAL_UNSPECIFIED; 
00526       result->token[0] = '\0';
00527       return -1;
00528    } 
00529 
00530    res = 1;
00531    /* Strip leading and trailing brackets */
00532    destination[strlen(destination) - 1] = '\0';
00533    switch(protocol) {
00534       case OSPE_DEST_PROT_H323_SETUP:
00535          ast_log(LOG_DEBUG, "OSP: protocol '%d'\n", protocol);
00536          ast_copy_string(result->tech, "H323", sizeof(result->tech));
00537          snprintf(result->dest, sizeof(result->dest), "%s@%s", called, destination + 1);
00538          ast_copy_string(result->calling, calling, sizeof(result->calling));
00539          break;
00540       case OSPE_DEST_PROT_SIP:
00541          ast_log(LOG_DEBUG, "OSP: protocol '%d'\n", protocol);
00542          ast_copy_string(result->tech, "SIP", sizeof(result->tech));
00543          snprintf(result->dest, sizeof(result->dest), "%s@%s", called, destination + 1);
00544          ast_copy_string(result->calling, calling, sizeof(result->calling));
00545          break;
00546       case OSPE_DEST_PROT_IAX:
00547          ast_log(LOG_DEBUG, "OSP: protocol '%d'\n", protocol);
00548          ast_copy_string(result->tech, "IAX", sizeof(result->tech));
00549          snprintf(result->dest, sizeof(result->dest), "%s@%s", called, destination + 1);
00550          ast_copy_string(result->calling, calling, sizeof(result->calling));
00551          break;
00552       default:
00553          ast_log(LOG_DEBUG, "OSP: Unknown protocol '%d'\n", protocol);
00554          *reason = OSPC_FAIL_PROTOCOL_ERROR; 
00555          result->token[0] = '\0';
00556          res = 0;
00557    }
00558 
00559    return res;
00560 }
00561 
00562 /*!
00563  * \brief Convert Asterisk status to TC code
00564  * \param cause Asterisk hangup cause
00565  * \return OSP TC code
00566  */
00567 static enum OSPEFAILREASON asterisk2osp(int cause)
00568 {
00569    return (enum OSPEFAILREASON)cause;
00570 }
00571 
00572 /*!
00573  * \brief OSP Authentication function
00574  * \param provider OSP provider context name
00575  * \param transaction OSP transaction handle, output
00576  * \param source Source of inbound call
00577  * \param calling Calling number
00578  * \param called Called number
00579  * \param token OSP token, may be empty
00580  * \param timelimit Call duration limit, output
00581  * \return 1 Authenricated, 0 Unauthenticated, -1 Error
00582  */
00583 static int osp_auth(const char* provider, int* transaction, const char* source, const char* calling, const char* called, const char* token, unsigned int* timelimit)
00584 {
00585    int res;
00586    int policy = OSP_AUTH_YES;
00587    char dest[OSP_NORSTR_SIZE];
00588 
00589    *transaction = OSP_INVALID_HANDLE;
00590    *timelimit = OSP_DEF_TIMELIMIT;
00591    res = osp_get_policy(provider, &policy);
00592    if (!res) {
00593       ast_log(LOG_DEBUG, "OSP: Unabe to find OSP authentication policy\n");
00594       return res;
00595    }
00596 
00597    switch (policy) {
00598       case OSP_AUTH_NO:
00599          res = 1;
00600          break;
00601       case OSP_AUTH_EXCLUSIVE:
00602          if (ast_strlen_zero(token)) {
00603             res = 0;
00604          } else if ((res = osp_create_transaction(provider, transaction, sizeof(dest), dest)) <= 0) {
00605             ast_log(LOG_DEBUG, "OSP: Unable to generate transaction handle\n");
00606             *transaction = OSP_INVALID_HANDLE;
00607             res = 0;
00608          } else if((res = osp_validate_token(*transaction, source, dest, calling, called, token, timelimit)) <= 0) {
00609             OSPPTransactionRecordFailure(*transaction, OSPC_FAIL_CALL_REJECTED);
00610          }
00611          break;
00612       case OSP_AUTH_YES:
00613       default:
00614          if (ast_strlen_zero(token)) {
00615             res = 1;
00616          } else if ((res = osp_create_transaction(provider, transaction, sizeof(dest), dest)) <= 0) {
00617             ast_log(LOG_DEBUG, "OSP: Unable to generate transaction handle\n");
00618             *transaction = OSP_INVALID_HANDLE;
00619             res = 0;
00620          } else if((res = osp_validate_token(*transaction, source, dest, calling, called, token, timelimit)) <= 0) {
00621             OSPPTransactionRecordFailure(*transaction, OSPC_FAIL_CALL_REJECTED);
00622          }
00623          break;
00624    }
00625 
00626    return res;
00627 }
00628 
00629 /*!
00630  * \brief OSP Lookup function
00631  * \param provider OSP provider context name
00632  * \param srcdev Source device of outbound call
00633  * \param calling Calling number
00634  * \param called Called number
00635  * \param result Lookup results
00636  * \return 1 Found , 0 No route, -1 Error
00637  */
00638 static int osp_lookup(const char* provider, const char* srcdev, const char* calling, const char* called, struct osp_result* result)
00639 {
00640    int res;
00641    char source[OSP_NORSTR_SIZE];
00642    unsigned int callidlen;
00643    char callid[OSPC_CALLID_MAXSIZE];
00644    char callingnum[OSP_NORSTR_SIZE];
00645    char callednum[OSP_NORSTR_SIZE];
00646    char destination[OSP_NORSTR_SIZE];
00647    unsigned int tokenlen;
00648    char token[OSP_TOKSTR_SIZE];
00649    char src[OSP_NORSTR_SIZE];
00650    char dev[OSP_NORSTR_SIZE];
00651    unsigned int dummy = 0;
00652    enum OSPEFAILREASON reason;
00653    int error;
00654 
00655    result->outhandle = OSP_INVALID_HANDLE;
00656    result->tech[0] = '\0';
00657    result->dest[0] = '\0';
00658    result->calling[0] = '\0';
00659    result->token[0] = '\0';
00660    result->numresults = 0;
00661    result->outtimelimit = OSP_DEF_TIMELIMIT;
00662 
00663    if ((res = osp_create_transaction(provider, &result->outhandle, sizeof(source), source)) <= 0) {
00664       ast_log(LOG_DEBUG, "OSP: Unable to generate transaction handle\n");
00665       result->outhandle = OSP_INVALID_HANDLE;
00666       if (result->inhandle != OSP_INVALID_HANDLE) {
00667          OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
00668       }
00669       return -1;
00670    }
00671 
00672    osp_convert_address(source, src, sizeof(src));
00673    osp_convert_address(srcdev, dev, sizeof(dev));
00674    result->numresults = OSP_DEF_DESTINATIONS;
00675    error = OSPPTransactionRequestAuthorisation(result->outhandle, src, dev, calling ? calling : "",
00676          OSPC_E164, called, OSPC_E164, NULL, 0, NULL, NULL, &result->numresults, &dummy, NULL);
00677    if (error != OSPC_ERR_NO_ERROR) {
00678       ast_log(LOG_DEBUG, "OSP: Unable to request authorization\n");
00679       result->numresults = 0;
00680       if (result->inhandle != OSP_INVALID_HANDLE) {
00681          OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
00682       }
00683       return -1;
00684    }
00685 
00686    if (!result->numresults) {
00687       ast_log(LOG_DEBUG, "OSP: No more destination\n");
00688       if (result->inhandle != OSP_INVALID_HANDLE) {
00689          OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
00690       }
00691       return 0;
00692    }
00693 
00694    callidlen = sizeof(callid);
00695    tokenlen = sizeof(token);
00696    error = OSPPTransactionGetFirstDestination(result->outhandle, 0, NULL, NULL, &result->outtimelimit, &callidlen, callid,
00697          sizeof(callednum), callednum, sizeof(callingnum), callingnum, sizeof(destination), destination, 0, NULL, &tokenlen, token);
00698    if (error != OSPC_ERR_NO_ERROR) {
00699       ast_log(LOG_DEBUG, "OSP: Unable to get first route\n");
00700       result->numresults = 0;
00701       result->outtimelimit = OSP_DEF_TIMELIMIT;
00702       if (result->inhandle != OSP_INVALID_HANDLE) {
00703          OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
00704       }
00705       return -1;
00706    }
00707 
00708    result->numresults--;
00709    result->outtimelimit = osp_choose_timelimit(result->intimelimit, result->outtimelimit);
00710    ast_log(LOG_DEBUG, "OSP: outtimelimit '%d'\n", result->outtimelimit);
00711    ast_log(LOG_DEBUG, "OSP: called '%s'\n", callednum);
00712    ast_log(LOG_DEBUG, "OSP: calling '%s'\n", callingnum);
00713    ast_log(LOG_DEBUG, "OSP: destination '%s'\n", destination);
00714    ast_log(LOG_DEBUG, "OSP: token size '%d'\n", tokenlen);
00715 
00716    if ((res = osp_check_destination(callednum, callingnum, destination, tokenlen, token, &reason, result)) > 0) {
00717       return 1;
00718    }
00719 
00720    if (!result->numresults) {
00721       ast_log(LOG_DEBUG, "OSP: No more destination\n");
00722       result->outtimelimit = OSP_DEF_TIMELIMIT;
00723       OSPPTransactionRecordFailure(result->outhandle, reason);
00724       if (result->inhandle != OSP_INVALID_HANDLE) {
00725          OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
00726       }
00727       return 0;
00728    }
00729 
00730    while(result->numresults) {
00731       callidlen = sizeof(callid);
00732       tokenlen = sizeof(token);
00733       error = OSPPTransactionGetNextDestination(result->outhandle, reason, 0, NULL, NULL, &result->outtimelimit, &callidlen, callid,
00734             sizeof(callednum), callednum, sizeof(callingnum), callingnum, sizeof(destination), destination, 0, NULL, &tokenlen, token);
00735       if (error == OSPC_ERR_NO_ERROR) {
00736          result->numresults--;
00737          result->outtimelimit = osp_choose_timelimit(result->intimelimit, result->outtimelimit);
00738          ast_log(LOG_DEBUG, "OSP: outtimelimit '%d'\n", result->outtimelimit);
00739          ast_log(LOG_DEBUG, "OSP: called '%s'\n", callednum);
00740          ast_log(LOG_DEBUG, "OSP: calling '%s'\n", callingnum);
00741          ast_log(LOG_DEBUG, "OSP: destination '%s'\n", destination);
00742          ast_log(LOG_DEBUG, "OSP: token size '%d'\n", tokenlen);
00743          if ((res = osp_check_destination(callednum, callingnum, destination, tokenlen, token, &reason, result)) > 0) {
00744             break;
00745          } else if (!result->numresults) {
00746             ast_log(LOG_DEBUG, "OSP: No more destination\n");
00747             OSPPTransactionRecordFailure(result->outhandle, reason);
00748             if (result->inhandle != OSP_INVALID_HANDLE) {
00749                OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
00750             }
00751             res = 0;
00752             break;
00753          }
00754       } else {
00755          ast_log(LOG_DEBUG, "OSP: Unable to get route, error '%d'\n", error);
00756          result->numresults = 0;
00757          result->outtimelimit = OSP_DEF_TIMELIMIT;
00758          if (result->inhandle != OSP_INVALID_HANDLE) {
00759             OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
00760          }
00761          res = -1;
00762          break;
00763       }
00764    }
00765    return res;
00766 }
00767 
00768 /*!
00769  * \brief OSP Lookup Next function
00770  * \param cause Asterisk hangup cuase
00771  * \param result Lookup results, in/output
00772  * \return 1 Found , 0 No route, -1 Error
00773  */
00774 static int osp_next(int cause, struct osp_result* result)
00775 {
00776    int res;
00777    unsigned int callidlen;
00778    char callid[OSPC_CALLID_MAXSIZE];
00779    char callingnum[OSP_NORSTR_SIZE];
00780    char callednum[OSP_NORSTR_SIZE];
00781    char destination[OSP_NORSTR_SIZE];
00782    unsigned int tokenlen;
00783    char token[OSP_TOKSTR_SIZE];
00784    enum OSPEFAILREASON reason;
00785    int error;
00786 
00787    result->tech[0] = '\0';
00788    result->dest[0] = '\0';
00789    result->calling[0] = '\0';
00790    result->token[0] = '\0';
00791    result->outtimelimit = OSP_DEF_TIMELIMIT;
00792 
00793    if (result->outhandle == OSP_INVALID_HANDLE) {
00794       ast_log(LOG_DEBUG, "OSP: Transaction handle undefined\n");
00795       result->numresults = 0;
00796       if (result->inhandle != OSP_INVALID_HANDLE) {
00797          OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
00798       }
00799       return -1;
00800    }
00801 
00802    reason = asterisk2osp(cause);
00803 
00804    if (!result->numresults) {
00805       ast_log(LOG_DEBUG, "OSP: No more destination\n");
00806       OSPPTransactionRecordFailure(result->outhandle, reason);
00807       if (result->inhandle != OSP_INVALID_HANDLE) {
00808          OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
00809       }
00810       return 0;
00811    }
00812 
00813    while(result->numresults) {
00814       callidlen = sizeof(callid);
00815       tokenlen = sizeof(token);
00816       error = OSPPTransactionGetNextDestination(result->outhandle, reason, 0, NULL, NULL, &result->outtimelimit, &callidlen,
00817             callid, sizeof(callednum), callednum, sizeof(callingnum), callingnum, sizeof(destination), destination, 0, NULL, &tokenlen, token);
00818       if (error == OSPC_ERR_NO_ERROR) {
00819          result->numresults--;
00820          result->outtimelimit = osp_choose_timelimit(result->intimelimit, result->outtimelimit);
00821          ast_log(LOG_DEBUG, "OSP: outtimelimit '%d'\n", result->outtimelimit);
00822          ast_log(LOG_DEBUG, "OSP: called '%s'\n", callednum);
00823          ast_log(LOG_DEBUG, "OSP: calling '%s'\n", callingnum);
00824          ast_log(LOG_DEBUG, "OSP: destination '%s'\n", destination);
00825          ast_log(LOG_DEBUG, "OSP: token size '%d'\n", tokenlen);
00826          if ((res = osp_check_destination(callednum, callingnum, destination, tokenlen, token, &reason, result)) > 0) {
00827             res = 1;
00828             break;
00829          } else if (!result->numresults) {
00830             ast_log(LOG_DEBUG, "OSP: No more destination\n");
00831             OSPPTransactionRecordFailure(result->outhandle, reason);
00832             if (result->inhandle != OSP_INVALID_HANDLE) {
00833                OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NO_ROUTE_TO_DEST);
00834             }
00835             res = 0;
00836             break;
00837          }
00838       } else {
00839          ast_log(LOG_DEBUG, "OSP: Unable to get route, error '%d'\n", error);
00840          result->token[0] = '\0';
00841          result->numresults = 0;
00842          result->outtimelimit = OSP_DEF_TIMELIMIT;
00843          if (result->inhandle != OSP_INVALID_HANDLE) {
00844             OSPPTransactionRecordFailure(result->inhandle, OSPC_FAIL_NORMAL_UNSPECIFIED);
00845          }
00846          res = -1;
00847          break;
00848       }
00849    }
00850 
00851    return res;
00852 }
00853 
00854 /*!
00855  * \brief OSP Finish function
00856  * \param handle OSP in/outbound transaction handle
00857  * \param recorded If failure reason has been recorded
00858  * \param cause Asterisk hangup cause
00859  * \param start Call start time
00860  * \param connect Call connect time
00861  * \param end Call end time
00862  * \param release Who release first, 0 source, 1 destination
00863  * \return 1 Success, 0 Failed, -1 Error
00864  */
00865 static int osp_finish(int handle, int recorded, int cause, time_t start, time_t connect, time_t end, unsigned int release)
00866 {
00867    int