diff --git a/src/modules/lost/functions.c b/src/modules/lost/functions.c index 7e62a8dd7a3..ae0249ae300 100644 --- a/src/modules/lost/functions.c +++ b/src/modules/lost/functions.c @@ -44,6 +44,8 @@ #include "pidf.h" #include "utilities.h" +#include "response.h" +#include "naptr.h" #define LOST_SUCCESS 200 #define LOST_CLIENT_ERROR 400 @@ -52,6 +54,10 @@ #define HELD_DEFAULT_TYPE "geodetic locationURI" #define HELD_DEFAULT_TYPE_LEN (sizeof(HELD_DEFAULT_TYPE) - 1) +#define NAPTR_LOST_SERVICE_HTTP "LoST:http" +#define NAPTR_LOST_SERVICE_HTTPS "LoST:https" +#define NAPTR_LIS_SERVICE_HELD "LIS:HELD" + extern httpc_api_t httpapi; extern int lost_geoloc_type; @@ -138,6 +144,7 @@ char *lost_held_type(char *type, int *exact, int *lgth) err: LM_ERR("no more private memory\n"); + /* clean up */ if(ret != NULL) { pkg_free(ret); } @@ -166,32 +173,56 @@ int lost_held_function(struct sip_msg *_m, char *_con, char *_pidf, char *_url, xmlNodePtr root = NULL; xmlNodePtr cur_node = NULL; - str did = {NULL, 0}; - str que = {NULL, 0}; - str con = {NULL, 0}; - str geo = {NULL, 0}; - str err = {NULL, 0}; - str res = {NULL, 0}; - str idhdr = {NULL, 0}; - str pidfuri = {NULL, 0}; - str rtype = {HELD_DEFAULT_TYPE, HELD_DEFAULT_TYPE_LEN}; - - int curlres = 0; + str geo = STR_NULL; /* return value geolocation uri */ + str res = STR_NULL; /* return value pidf */ + str err = STR_NULL; /* return value error */ + + str url = STR_NULL; + str did = STR_NULL; + str que = STR_NULL; + str con = STR_NULL; + str host = STR_NULL; + str name = STR_NULL; + str idhdr = STR_NULL; + str pidfuri = STR_NULL; + + static str rtype = STR_STATIC_INIT(HELD_DEFAULT_TYPE); + static str sheld = STR_STATIC_INIT(NAPTR_LIS_SERVICE_HELD); + + char ustr[MAX_URI_SIZE]; + char istr[NI_MAXHOST]; + char *ipstr = NULL; + char *lisurl = NULL; + + int len = 0; + int curl = 0; + int flag = 0; + int naptr = 0; int presence = 0; - if(_con == NULL || _pidf == NULL || _url == NULL || _err == NULL) { + if(_pidf == NULL || _url == NULL || _err == NULL) { LM_ERR("invalid parameter\n"); goto err; } + /* module parameter */ if(held_loc_type.len > 0) { rtype.s = held_loc_type.s; rtype.len = held_loc_type.len; } /* connection from parameter */ - if(fixup_get_svalue(_m, (gparam_p)_con, &con) != 0) { - LM_ERR("cannot get connection string\n"); - goto err; + if(_con) { + if(fixup_get_svalue(_m, (gparam_p)_con, &con) != 0) { + LM_ERR("cannot get connection string\n"); + goto err; + } + /* check if connection exists */ + if(con.s != NULL && con.len > 0) { + if(httpapi.http_connection_exists(&con) == 0) { + LM_ERR("connection: [%s] does not exist\n", con.s); + goto err; + } + } } /* id from parameter */ if(_id) { @@ -225,30 +256,15 @@ int lost_held_function(struct sip_msg *_m, char *_con, char *_pidf, char *_url, did.len = idhdr.len; } LM_INFO("### HELD id [%.*s]\n", did.len, did.s); - - /* check if connection exists */ - if(httpapi.http_connection_exists(&con) == 0) { - LM_ERR("connection: [%s] does not exist\n", con.s); - lost_free_string(&idhdr); - goto err; - } - /* assemble locationRequest */ held = lost_new_held(did, rtype, held_resp_time, held_exact_type); - if(held == NULL) { LM_ERR("held object allocation failed\n"); - lost_free_string(&idhdr); + lost_free_string(&idhdr); /* clean up */ goto err; } que.s = lost_held_location_request(held, &que.len); - - /* free memory */ - did.s = NULL; - did.len = 0; - lost_free_held(held); - lost_free_string(&idhdr); - + lost_free_held(held); /* clean up */ if(que.len == 0) { LM_ERR("held request document error\n"); que.s = NULL; @@ -258,17 +274,89 @@ int lost_held_function(struct sip_msg *_m, char *_con, char *_pidf, char *_url, LM_DBG("held location request: [%s]\n", que.s); /* send locationRequest to location server - HTTP POST */ - curlres = httpapi.http_connect(_m, &con, NULL, &res, mtheld, &que); + if(con.s != NULL && con.len > 0) { + + LM_DBG("using connection [%.*s]\n", con.len, con.s); + + /* send via connection */ + curl = httpapi.http_connect(_m, &con, NULL, &res, mtheld, &que); + } else { + /* we have no connection ... do a NAPTR lookup */ + if(lost_parse_host(did.s, &host, &flag) > 0) { + + LM_DBG("no conn. trying NATPR lookup [%.*s]\n", host.len, host.s); + + /* remove '[' and ']' from string (IPv6) */ + if(flag == AF_INET6) { + host.s++; + host.len = host.len - 2; + } + /* is it a name or ip ... check nameinfo (reverse lookup) */ + len = 0; + ipstr = lost_copy_string(host, &len); + if(len > 0) { + name.s = &(istr[0]); + name.len = NI_MAXHOST; + if(lost_get_nameinfo(ipstr, &name, flag) > 0) { + + LM_DBG("ip [%s] to name [%.*s]\n", ipstr, name.len, name.s); + + /* change ip string to name */ + host.s = name.s; + host.len = name.len; + } else { + + /* keep string */ + LM_DBG("no nameinfo for [%s]\n", ipstr); + + } + pkg_free(ipstr); /* clean up */ + } + url.s = &(ustr[0]); + url.len = MAX_URI_SIZE; + if((naptr = lost_naptr_lookup(host, &sheld, &url)) == 0) { + LM_ERR("NAPTR failed on [%.*s]\n", host.len, host.s); + lost_free_string(&que); /* clean up */ + lost_free_string(&idhdr); + goto err; + } + } else { + LM_ERR("failed to get location service for [%.*s]\n", did.len, did.s); + lost_free_string(&que); /* clean up */ + lost_free_string(&idhdr); + goto err; + } + + LM_DBG("NATPR lookup returned [%.*s]\n", url.len, url.s); + + /* curl doesn't like str */ + len = 0; + lisurl = lost_copy_string(url, &len); + /* send to service */ + if(len > 0) { + curl = httpapi.http_client_query(_m, lisurl, &res, que.s, mtheld); + pkg_free(lisurl); /*clean up */ + } else { + goto err; + } + } /* only HTTP 2xx responses are accepted */ - if(curlres >= 300 || curlres < 100) { - LM_ERR("[%.*s] failed with error: %d\n", con.len, con.s, curlres); + if(curl >= 300 || curl < 100) { + if(con.s != NULL && con.len > 0) { + LM_ERR("[%.*s] failed with error: %d\n", con.len, con.s, curl); + } else { + LM_ERR("[%.*s] failed with error: %d\n", url.len, url.s, curl); + } lost_free_string(&res); goto err; } - LM_DBG("[%.*s] returned: %d\n", con.len, con.s, curlres); + LM_DBG("[%.*s] returned: %d\n", con.len, con.s, curl); - /* free memory */ + did.s = NULL; + did.len = 0; + /* clean up */ + lost_free_string(&idhdr); lost_free_string(&que); /* read and parse the returned xml */ doc = xmlReadMemory(res.s, res.len, 0, NULL, @@ -288,7 +376,7 @@ int lost_held_function(struct sip_msg *_m, char *_con, char *_pidf, char *_url, LM_ERR("empty xml document\n"); goto err; } - /* check the root element ... shall be locationResponse, or errors */ + /* check the root element ... shall be locationResponse, or error */ if(xmlStrcmp(root->name, (const xmlChar *)"locationResponse") == 0) { LM_DBG("HELD location response [%.*s]\n", res.len, res.s); @@ -310,8 +398,7 @@ int lost_held_function(struct sip_msg *_m, char *_con, char *_pidf, char *_url, geo.s = lost_trim_content(geo.s, &geo.len); } } - if(xmlStrcmp(cur_node->name, (const xmlChar *)"presence") - == 0) { + if(xmlStrcmp(cur_node->name, (const xmlChar *)"presence") == 0) { LM_DBG("*** node '%s' found\n", cur_node->name); @@ -320,29 +407,22 @@ int lost_held_function(struct sip_msg *_m, char *_con, char *_pidf, char *_url, } } } - /* if we do not have a presence node but a location URI */ /* dereference pidf.lo at location server via HTTP GET */ - if((presence == 0) && (geo.len > 0)) { - + if((presence == 0) && (geo.s != NULL && geo.len > 0)) { LM_INFO("presence node not found in HELD response, trying URI " "...\n"); - - curlres = - httpapi.http_client_query(_m, geo.s, &pidfuri, NULL, NULL); + curl = httpapi.http_client_query(_m, geo.s, &pidfuri, NULL, NULL); /* only HTTP 2xx responses are accepted */ - if(curlres >= 300 || curlres < 100) { - LM_ERR("dereferencing location failed: %d\n", curlres); - /* free memory */ + if(curl >= 300 || curl < 100) { + LM_ERR("dereferencing location failed: %d\n", curl); + /* clean up */ lost_free_string(&pidfuri); goto err; } - if(pidfuri.len == 0) { - LM_WARN("HELD location request failed [%.*s]\n", geo.len, geo.s); - } else { LM_DBG("HELD location response [%.*s]\n", pidfuri.len, @@ -352,14 +432,15 @@ int lost_held_function(struct sip_msg *_m, char *_con, char *_pidf, char *_url, res.len = pidfuri.len; } } + /* error received */ } else if(xmlStrcmp(root->name, (const xmlChar *)"error") == 0) { LM_DBG("HELD error response [%.*s]\n", res.len, res.s); - /* get the error patterm */ + /* get the error property */ err.s = lost_get_property(root, (char *)"code", &err.len); if(err.len == 0) { - LM_ERR("error - code property not found: [%.*s]\n", res.len, res.s); + LM_ERR("error - property not found: [%.*s]\n", res.len, res.s); goto err; } LM_WARN("locationRequest error response: [%.*s]\n", err.len, err.s); @@ -367,8 +448,9 @@ int lost_held_function(struct sip_msg *_m, char *_con, char *_pidf, char *_url, LM_ERR("root element is not valid: [%.*s]\n", res.len, res.s); goto err; } + + /* clean up */ xmlFreeDoc(doc); - doc = NULL; /* set writeable pvars */ pvpidf.rs = res; @@ -422,63 +504,85 @@ int lost_function(struct sip_msg *_m, char *_con, char *_uri, char *_name, p_loc_t loc = NULL; p_geolist_t geolist = NULL; - int geotype; - - str url = {NULL, 0}; - str uri = {NULL, 0}; - str urn = {NULL, 0}; - str err = {NULL, 0}; - str req = {NULL, 0}; - str con = {NULL, 0}; - str ret = {NULL, 0}; - str name = {NULL, 0}; - str pidf = {NULL, 0}; - str geohdr = {NULL, 0}; - str pidfhdr = {NULL, 0}; + p_fsr_t fsrdata = NULL; + + str name = STR_NULL; /* return value displayName */ + str uri = STR_NULL; /* return value uri */ + str err = STR_NULL; /* return value error */ + + str tmp = STR_NULL; + str url = STR_NULL; + str urn = STR_NULL; + str req = STR_NULL; + str con = STR_NULL; + str ret = STR_NULL; + str pidf = STR_NULL; + str geohdr = STR_NULL; + str oldurl = STR_NULL; + str losturl = STR_NULL; + + static str shttp = STR_STATIC_INIT(NAPTR_LOST_SERVICE_HTTP); + static str shttps = STR_STATIC_INIT(NAPTR_LOST_SERVICE_HTTPS); struct msg_start *fl; + + char ustr[MAX_URI_SIZE]; char *search = NULL; char *geoval = NULL; - int curlres = 0; - int geoitems = 0; - xmlDocPtr doc = NULL; - xmlNodePtr root = NULL; + int geotype = 0; + int redirect = 0; + int curl = 0; + int naptr = 0; + int geoitems = 0; if(_con == NULL || _uri == NULL || _name == NULL || _err == NULL) { LM_ERR("invalid parameter\n"); goto err; } - if(fixup_get_svalue(_m, (gparam_p)_con, &con) != 0) { - LM_ERR("cannot get connection string\n"); - goto err; + /* connection from parameter */ + if(_con) { + if(fixup_get_svalue(_m, (gparam_p)_con, &con) != 0) { + LM_ERR("cannot get connection string\n"); + goto err; + } + /* check if connection exists */ + if(con.s != NULL && con.len > 0) { + if(httpapi.http_connection_exists(&con) == 0) { + LM_WARN("connection: [%.*s] does not exist\n", con.len, con.s); + /* check if NAPTR lookup works with connection parameter */ + losturl.s = &(ustr[0]); + losturl.len = MAX_URI_SIZE; + if((naptr = lost_naptr_lookup(con, &shttps, &losturl)) == 0) { + naptr = lost_naptr_lookup(con, &shttp, &losturl); + } + if(naptr == 0) { + LM_ERR("NAPTR failed on [%.*s]\n", con.len, con.s); + goto err; + } + } + } } /* urn from parameter */ if(_urn) { if(fixup_get_svalue(_m, (gparam_p)_urn, &urn) != 0) { - LM_ERR("cannot get service urn\n"); + LM_ERR("cannot get service urn parameter\n"); goto err; } } /* urn from request line */ if(urn.len == 0) { - LM_WARN("no sevice urn parameter, trying request line ...\n"); + + LM_DBG("no service urn parameter, trying request line ...\n"); + fl = &(_m->first_line); urn.len = fl->u.request.uri.len; urn.s = fl->u.request.uri.s; } /* check urn scheme */ - if(urn.len > 3) { - search = urn.s; - if(((*(search + 0) == 'u') || (*(search + 0) == 'U')) - && ((*(search + 1) == 'r') || (*(search + 1) == 'R')) - && ((*(search + 2) == 'n') || (*(search + 2) == 'N')) - && (*(search + 3) == ':')) { - LM_INFO("### LOST urn\t[%.*s]\n", urn.len, urn.s); - } else { - LM_ERR("service urn not found\n"); - goto err; - } + search = urn.s; + if(is_urn(search) > 0) { + LM_INFO("### LOST urn\t[%.*s]\n", urn.len, urn.s); } else { LM_ERR("service urn not found\n"); goto err; @@ -486,44 +590,35 @@ int lost_function(struct sip_msg *_m, char *_con, char *_uri, char *_name, /* pidf from parameter */ if(_pidf) { if(fixup_get_svalue(_m, (gparam_p)_pidf, &pidf) != 0) { - LM_WARN("cannot get pidf-lo parameter\n"); + LM_ERR("cannot get pidf parameter\n"); } else { - LM_DBG("parsing pidf-lo from paramenter\n"); + LM_DBG("parsing pidf parameter ...\n"); - if(pidf.len > 0) { + if(pidf.s != NULL && pidf.len > 0) { - LM_DBG("pidf-lo: [%.*s]\n", pidf.len, pidf.s); + LM_DBG("pidf: [%.*s]\n", pidf.len, pidf.s); - /* parse the pidf-lo */ + /* parse the pidf and get loc object */ loc = lost_parse_pidf(pidf, urn); - /* free memory */ - pidf.s = NULL; - pidf.len = 0; - } else { - LM_WARN("no valid pidf parameter ...\n"); } } } - - /* no pidf-lo so far ... check geolocation header */ + /* neither valifd pidf parameter nor loc ... check geolocation header */ if(loc == NULL) { LM_DBG("looking for geolocation header ...\n"); - geohdr.s = lost_get_geolocation_header(_m, &geohdr.len); - if(geohdr.len == 0) { + if(lost_get_geolocation_header(_m, &geohdr) == 0) { LM_ERR("geolocation header not found\n"); - goto err; } - LM_DBG("geolocation header found\n"); + LM_DBG("parsing geolocation header ...\n"); /* parse Geolocation header */ geolist = lost_new_geoheader_list(geohdr, &geoitems); if(geoitems == 0) { LM_ERR("invalid geolocation header\n"); - lost_free_string(&geohdr); goto err; } @@ -535,7 +630,6 @@ int lost_function(struct sip_msg *_m, char *_con, char *_uri, char *_name, lost_reverse_geoheader_list(&geolist); } - switch(lost_geoloc_type) { case ANY: /* type: 0 */ geoval = lost_get_geoheader_value(geolist, ANY, &geotype); @@ -580,36 +674,26 @@ int lost_function(struct sip_msg *_m, char *_con, char *_uri, char *_name, break; } - if(geoval == NULL) { LM_ERR("invalid geolocation header\n"); - /* free memory */ - lost_delete_geoheader_list(geolist); - lost_free_string(&geohdr); goto err; } - LM_INFO("### LOST loc\t[%s]\n", geoval); - + /* clean up */ + pidf.s = NULL; + pidf.len = 0; /* use location by value */ if(geotype == CID) { - /* get body part - filter=>content-indirection */ pidf.s = get_body_part_by_filter(_m, 0, 0, geoval, NULL, &pidf.len); - if(pidf.len > 0) { + if(pidf.s != NULL && pidf.len > 0) { LM_DBG("LbV pidf-lo: [%.*s]\n", pidf.len, pidf.s); - /* parse the pidf-lo */ - loc = lost_parse_pidf(pidf, urn); - /* free memory */ - pidf.s = NULL; - pidf.len = 0; } else { LM_WARN("no multipart body found\n"); } } - /* use location by reference */ if((geotype == HTTPS) || (geotype == HTTP)) { url.s = geoval; @@ -617,60 +701,44 @@ int lost_function(struct sip_msg *_m, char *_con, char *_uri, char *_name, /* ! dereference pidf.lo at location server - HTTP GET */ /* ! requires hack in http_client module */ /* ! functions.c => http_client_query => query_params.oneline = 0; */ - curlres = - httpapi.http_client_query(_m, url.s, &pidfhdr, NULL, NULL); - /* free memory */ + curl = httpapi.http_client_query(_m, url.s, &ret, NULL, NULL); url.s = NULL; url.len = 0; /* only HTTP 2xx responses are accepted */ - if(curlres >= 300 || curlres < 100) { - LM_ERR("http GET failed with error: %d\n", curlres); - /* free memory */ - lost_delete_geoheader_list(geolist); - lost_free_string(&pidfhdr); - lost_free_string(&geohdr); + if(curl >= 300 || curl < 100) { + LM_ERR("http GET failed with error: %d\n", curl); + /* clean up */ + lost_free_string(&ret); goto err; } - - pidf.s = pidfhdr.s; - pidf.len = pidfhdr.len; - - if(pidf.len > 0) { + pidf.s = ret.s; + pidf.len = ret.len; + if(pidf.s != NULL && pidf.len > 0) { LM_DBG("LbR pidf-lo: [%.*s]\n", pidf.len, pidf.s); - /* parse the pidf-lo */ - loc = lost_parse_pidf(pidf, urn); - /* free memory */ - pidf.s = NULL; - pidf.len = 0; } else { LM_WARN("dereferencing location failed\n"); } } - /* free memory */ + /* clean up */ lost_delete_geoheader_list(geolist); - lost_free_string(&geohdr); - lost_free_string(&pidfhdr); + lost_free_string(&ret); } - - if(loc == NULL) { + if(pidf.s == NULL && pidf.len == 0) { LM_ERR("location object not found\n"); goto err; } - - /* check if connection exits */ - if(httpapi.http_connection_exists(&con) == 0) { - LM_ERR("connection: [%.*s] does not exist\n", con.len, con.s); + /* parse the pidf and get loc object */ + loc = lost_parse_pidf(pidf, urn); + if(loc == NULL) { + LM_ERR("parsing pidf failed\n"); goto err; } /* assemble findService request */ req.s = lost_find_service_request(loc, &req.len); - /* free memory */ - lost_free_loc(loc); - loc = NULL; - - if(req.len == 0) { + lost_free_loc(loc); /* clean up */ + if(req.s == NULL && req.len == 0) { LM_ERR("lost request failed\n"); goto err; } @@ -678,18 +746,19 @@ int lost_function(struct sip_msg *_m, char *_con, char *_uri, char *_name, LM_DBG("findService request: [%.*s]\n", req.len, req.s); /* send findService request to mapping server - HTTP POST */ - curlres = httpapi.http_connect(_m, &con, NULL, &ret, mtlost, &req); + if(naptr) { + curl = httpapi.http_client_query(_m, url.s, &ret, req.s, mtlost); + } else { + curl = httpapi.http_connect(_m, &con, NULL, &ret, mtlost, &req); + } /* only HTTP 2xx responses are accepted */ - if(curlres >= 300 || curlres < 100) { - LM_ERR("[%.*s] failed with error: %d\n", con.len, con.s, curlres); + if(curl >= 300 || curl < 100) { + LM_ERR("[%.*s] failed with error: %d\n", con.len, con.s, curl); lost_free_string(&ret); goto err; } - LM_DBG("[%.*s] returned: %d\n", con.len, con.s, curlres); - - /* free memory */ - lost_free_string(&req); + LM_DBG("[%.*s] returned: %d\n", con.len, con.s, curl); if(ret.len == 0) { LM_ERR("findService request failed\n"); @@ -698,70 +767,117 @@ int lost_function(struct sip_msg *_m, char *_con, char *_uri, char *_name, LM_DBG("findService response: [%.*s]\n", ret.len, ret.s); - /* read and parse the returned xml */ - doc = xmlReadMemory(ret.s, ret.len, 0, 0, - XML_PARSE_NOBLANKS | XML_PARSE_NONET | XML_PARSE_NOCDATA); - - if(doc == NULL) { - LM_ERR("invalid xml document: [%.*s]\n", ret.len, ret.s); - doc = xmlRecoverMemory(ret.s, ret.len); - if(doc == NULL) { - LM_ERR("xml document recovery failed on: [%.*s]\n", ret.len, ret.s); - goto err; - } - - LM_DBG("xml document recovered\n"); - } - root = xmlDocGetRootElement(doc); - if(root == NULL) { - LM_ERR("empty xml document: [%.*s]\n", ret.len, ret.s); - /* free memory */ - lost_free_string(&ret); - goto err; - } - /* check the root element, shall be findServiceResponse, or errors */ - if((!xmlStrcmp(root->name, (const xmlChar *)"findServiceResponse"))) { - /* get the uri element */ - uri.s = lost_get_content(root, uri_element, &uri.len); - if(uri.len == 0) { - LM_ERR("uri element not found: [%.*s]\n", ret.len, ret.s); - /* free memory */ - lost_free_string(&ret); - goto err; - } - LM_INFO("### LOST uri\t[%.*s]\n", uri.len, uri.s); - /* get the displayName element */ - name.s = lost_get_content(root, name_element, &name.len); - if(name.len == 0) { - LM_ERR("displayName element not found: [%.*s]\n", ret.len, ret.s); - /* free memory */ - lost_free_string(&ret); - goto err; - } - LM_INFO("### LOST din\t[%.*s]\n", name.len, name.s); - } else if((!xmlStrcmp(root->name, (const xmlChar *)"errors"))) { - - LM_DBG("findService error response received\n"); - - /* get the error patterm */ - err.s = lost_get_childname(root, errors_element, &err.len); - LM_DBG("findService error response: [%.*s]\n", err.len, err.s); - if(err.len == 0) { - LM_ERR("error pattern element not found: [%.*s]\n", ret.len, ret.s); - /* free memory */ - lost_free_string(&ret); - goto err; + /* at least parse one request */ + redirect = 1; + while(redirect) { + fsrdata = lost_parse_findServiceResponse(ret); + lost_print_findServiceResponse(fsrdata); + switch(fsrdata->category) { + case RESPONSE: + if(fsrdata->uri != NULL) { + /* get the first uri element */ + if((tmp.s = fsrdata->uri->value) != NULL) { + tmp.len = strlen(fsrdata->uri->value); + uri.s = lost_copy_string(tmp, &uri.len); + } + } else { + LM_ERR("uri not found: [%.*s]\n", ret.len, ret.s); + goto err; + } + if(fsrdata->mapping != NULL) { + /* get the displayName element */ + if((tmp.s = fsrdata->mapping->name->text) != NULL) { + tmp.len = strlen(fsrdata->mapping->name->text); + name.s = lost_copy_string(tmp, &name.len); + } + } else { + LM_ERR("name not found: [%.*s]\n", ret.len, ret.s); + goto err; + } + /* we are done */ + redirect = 0; + break; + case ERROR: + /* get the errors element */ + if(fsrdata->errors != NULL) { + if((tmp.s = fsrdata->errors->issue->type) != NULL) { + tmp.len = strlen(fsrdata->errors->issue->type); + err.s = lost_copy_string(tmp, &err.len); + } + /* clean up */ + tmp.s = NULL; + tmp.len = 0; + } else { + LM_ERR("errors not found: [%.*s]\n", ret.len, ret.s); + goto err; + } + /* we are done */ + redirect = 0; + break; + case REDIRECT: + /* get the target element */ + if(fsrdata->redirect != NULL) { + if((tmp.s = fsrdata->redirect->target) != NULL) { + tmp.len = strlen(fsrdata->redirect->target); + url.s = &(ustr[0]); + url.len = MAX_URI_SIZE; + if((naptr = lost_naptr_lookup(tmp, &shttps, &url)) + == 0) { + naptr = lost_naptr_lookup(tmp, &shttp, &url); + } + if(naptr == 0) { + LM_ERR("NAPTR failed on [%.*s]\n", tmp.len, tmp.s); + goto err; + } + /* clean up */ + tmp.s = NULL; + tmp.len = 0; + /* check loop */ + if(oldurl.s != NULL && oldurl.len > 0) { + if(str_strcasecmp(&url, &oldurl) == 0) { + LM_ERR("loop detected: " + "[%.*s]<-->[%.*s]\n", + oldurl.len, oldurl.s, url.len, url.s); + goto err; + } + } + /* remember the redirect target */ + oldurl.s = lost_copy_string(url, &oldurl.len); + /* clean up */ + lost_free_findServiceResponse(fsrdata); + lost_free_string(&ret); + /* send request */ + curl = httpapi.http_client_query( + _m, url.s, &ret, req.s, mtlost); + url.s = NULL; + url.len = 0; + /* only HTTP 2xx responses are accepted */ + if(curl >= 300 || curl < 100) { + LM_ERR("http GET failed with error: %d\n", curl); + goto err; + } + /* once more ... we got a redirect */ + redirect = 1; + } + } else { + LM_ERR("redirect element not found: [%.*s]\n", ret.len, + ret.s); + goto err; + } + break; + case OTHER: + default: + LM_ERR("pidf is not valid: [%.*s]\n", ret.len, ret.s); + goto err; + break; } - LM_WARN("findService error response: [%.*s]\n", err.len, err.s); - } else { - LM_ERR("root element is not valid: [%.*s]\n", ret.len, ret.s); - /* free memory */ - lost_free_string(&ret); - goto err; } - /* free memory */ + /* clean up */ + lost_free_findServiceResponse(fsrdata); lost_free_string(&ret); + lost_free_string(&req); + lost_free_string(&oldurl); /* set writable pvars */ pvname.rs = name; @@ -791,14 +907,25 @@ int lost_function(struct sip_msg *_m, char *_con, char *_uri, char *_name, return (err.len > 0) ? LOST_SERVER_ERROR : LOST_SUCCESS; err: - /* free memory */ - if(doc != NULL) { - xmlFreeDoc(doc); - doc = NULL; + /* clean up */ + if(fsrdata != NULL) { + lost_free_findServiceResponse(fsrdata); + } + if(geolist != NULL) { + lost_delete_geoheader_list(geolist); + } + if(oldurl.s != NULL) { + lost_free_string(&oldurl); } if(loc != NULL) { lost_free_loc(loc); } + if(ret.s != NULL && ret.len > 0) { + lost_free_string(&ret); + } + if(req.s != NULL && req.len > 0) { + lost_free_string(&req); + } return LOST_CLIENT_ERROR; } diff --git a/src/modules/lost/lost.c b/src/modules/lost/lost.c index a2dd2498ad6..6b367d66892 100644 --- a/src/modules/lost/lost.c +++ b/src/modules/lost/lost.c @@ -155,7 +155,10 @@ static int child_init(int rank) static void destroy(void) { - pkg_free(held_loc_type.s); + if(held_loc_type.s != NULL && held_loc_type.len > 0) { + pkg_free(held_loc_type.s); + held_loc_type.len = 0; + } /* do nothing */ } diff --git a/src/modules/lost/naptr.c b/src/modules/lost/naptr.c new file mode 100644 index 00000000000..4228c05161e --- /dev/null +++ b/src/modules/lost/naptr.c @@ -0,0 +1,254 @@ +/* + * lost module naptr functions + * thankfully taken over from the enum module + * + * Copyright (C) 2021 Wolfgang Kampichler + * DEC112, FREQUENTIS AG + * + * This file is part of Kamailio, a free SIP server. + * + * Kamailio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * Kamailio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +/*! + * \file + * \brief Kamailio lost :: naptr + * \ingroup lost + * Module: \ref lost + */ + +#include "../../core/resolve.h" +#include "../../core/strutils.h" +#include "../../core/qvalue.h" + +/* Checks if NAPTR record has flag u and its services field + * LoST:https or LOST:http + * LIS:HELD + */ +static inline int service_match(struct naptr_rdata *naptr, str *service) +{ + if(service->len == 0) { + return 0; + } + + /* LoST:https or LOST:http or LIS:HELD */ + if(naptr->flags_len == 1) { + return (((naptr->flags[0] == 'u') || (naptr->flags[0] == 'U')) + && (naptr->services_len == service->len) + && (strncasecmp(naptr->services, service->s, service->len) == 0)); + } + + /* LIS:HELD domain */ + if(naptr->flags_len == 0) { + return ((naptr->services_len == service->len) + && (strncasecmp(naptr->services, service->s, service->len) == 0)); + } + + /* no matching service found */ + return 0; +} + +/* Parse NAPTR regexp field of the form !pattern!replacement! and return its + * components in pattern and replacement parameters. Regexp field starts at + * address first and is len characters long. + */ +static inline int parse_naptr_regexp( + char *first, int len, str *pattern, str *replacement) +{ + char *second, *third; + + if(len > 0) { + if(*first == '!') { + second = (char *)memchr((void *)(first + 1), '!', len - 1); + if(second) { + len = len - (second - first + 1); + if(len > 0) { + third = memchr(second + 1, '!', len); + if(third) { + pattern->len = second - first - 1; + pattern->s = first + 1; + replacement->len = third - second - 1; + replacement->s = second + 1; + return 1; + } else { + LM_ERR("Third ! missing from regexp\n"); + return -1; + } + } else { + LM_ERR("Third ! missing from regexp\n"); + return -2; + } + } else { + LM_ERR("Second ! missing from regexp\n"); + return -3; + } + } else { + LM_ERR("First ! missing from regexp\n"); + return -4; + } + } else { + LM_ERR("Regexp missing\n"); + return -5; + } +} + +/* + * Tests if one result record is "greater" that the other. Non-NAPTR records + * greater that NAPTR record. An invalid NAPTR record is greater than a + * valid one. Valid NAPTR records are compared based on their + * (order,preference). + */ +static inline int naptr_greater(struct rdata *a, struct rdata *b) +{ + struct naptr_rdata *na, *nb; + + if(a->type != T_NAPTR) + return 1; + if(b->type != T_NAPTR) + return 0; + + na = (struct naptr_rdata *)a->rdata; + if(na == 0) + return 1; + + nb = (struct naptr_rdata *)b->rdata; + if(nb == 0) + return 0; + + return (((na->order) << 16) + na->pref) > (((nb->order) << 16) + nb->pref); +} + +/* + * Bubble sorts result record list according to naptr (order,preference). + */ +static inline void naptr_sort(struct rdata **head) +{ + struct rdata *p, *q, *r, *s, *temp, *start; + + /* r precedes p and s points to the node up to which comparisons + are to be made */ + + s = NULL; + start = *head; + while(s != start->next) { + r = p = start; + q = p->next; + while(p != s) { + if(naptr_greater(p, q)) { + if(p == start) { + temp = q->next; + q->next = p; + p->next = temp; + start = q; + r = q; + } else { + temp = q->next; + q->next = p; + p->next = temp; + r->next = q; + r = q; + } + } else { + r = p; + p = p->next; + } + q = p->next; + if(q == s) + s = p; + } + } + *head = start; +} + +/* + * NAPTR lookup on hostname & service, returns result as string + */ +int lost_naptr_lookup(str hostname, str *service, str *result) +{ + struct rdata *head; + struct rdata *l; + struct naptr_rdata *naptr; + + str pattern, replacement; + + head = get_record(hostname.s, T_NAPTR, RES_ONLY_TYPE); + + if(head == 0) { + LM_DBG("no NAPTR record found for [%.*s]\n", hostname.len, hostname.s); + return 0; + } + + naptr_sort(&head); + + /* we have the naptr records, loop and find an srv record with */ + /* same ip address as source ip address, if we do then true is returned */ + + for(l = head; l; l = l->next) { + + if(l->type != T_NAPTR) + continue; /*should never happen*/ + naptr = (struct naptr_rdata *)l->rdata; + + if(naptr == 0) { + LM_ERR("no rdata in DNS response\n"); + free_rdata_list(head); + return 0; + } + + LM_DBG("NAPTR query on %.*s: order %u, pref %u, flen %u, flags " + "'%.*s', slen %u, services '%.*s', rlen %u, " + "regexp '%.*s'\n", + hostname.len, hostname.s, naptr->order, naptr->pref, + naptr->flags_len, (int)(naptr->flags_len), ZSW(naptr->flags), + naptr->services_len, (int)(naptr->services_len), + ZSW(naptr->services), naptr->regexp_len, + (int)(naptr->regexp_len), ZSW(naptr->regexp)); + + if(service_match(naptr, service) == 0) { + continue; + } + + if(parse_naptr_regexp(&(naptr->regexp[0]), naptr->regexp_len, &pattern, + &replacement) + < 0) { + free_rdata_list(head); /*clean up*/ + LM_ERR("parsing of NAPTR regexp failed\n"); + return 0; + } + /* Avoid making copies of pattern and replacement */ + pattern.s[pattern.len] = (char)0; + replacement.s[replacement.len] = (char)0; + /* replace hostname */ + if(reg_replace(pattern.s, replacement.s, &(hostname.s[0]), result) + < 0) { + pattern.s[pattern.len] = '!'; + replacement.s[replacement.len] = '!'; + LM_ERR("regexp replace failed\n"); + free_rdata_list(head); /*clean up*/ + return 0; + } else { + + LM_DBG("resulted in replacement: '%.*s'\n", result->len, + ZSW(result->s)); + + free_rdata_list(head); /*clean up*/ + return 1; + } + } + + /* must not have found the record */ + return 0; +} \ No newline at end of file diff --git a/src/modules/lost/naptr.h b/src/modules/lost/naptr.h new file mode 100644 index 00000000000..c55a684ff61 --- /dev/null +++ b/src/modules/lost/naptr.h @@ -0,0 +1,38 @@ +/* + * lost module naptr functions + * + * Copyright (C) 2021 Wolfgang Kampichler + * DEC112, FREQUENTIS AG + * + * This file is part of Kamailio, a free SIP server. + * + * Kamailio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * Kamailio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +/*! + * \file + * \brief Kamailio lost :: naptr + * \ingroup lost + * Module: \ref lost + */ + +#ifndef LOST_NAPTR_H +#define LOST_NAPTR_H + +/* NAPTR lookup and host string replacement */ +int lost_naptr_lookup(str, str *, str *); + +#endif \ No newline at end of file diff --git a/src/modules/lost/pidf.c b/src/modules/lost/pidf.c index 927d39fbe51..73ba530a75a 100644 --- a/src/modules/lost/pidf.c +++ b/src/modules/lost/pidf.c @@ -123,7 +123,10 @@ char *xmlNodeGetNodeContentByName( xmlNodePtr xmlDocGetNodeByName(xmlDocPtr doc, const char *name, const char *ns) { xmlNodePtr cur = doc->children; - return xmlNodeGetNodeByName(cur, name, ns); + if(cur) + return xmlNodeGetNodeByName(cur, name, ns); + else + return NULL; } char *xmlDocGetNodeContentByName( diff --git a/src/modules/lost/response.c b/src/modules/lost/response.c new file mode 100644 index 00000000000..6ce61f3f9c9 --- /dev/null +++ b/src/modules/lost/response.c @@ -0,0 +1,946 @@ +/* + * lost module LoST response parsing functions + * + * Copyright (C) 2021 Wolfgang Kampichler + * DEC112, FREQUENTIS AG + * + * This file is part of Kamailio, a free SIP server. + * + * Kamailio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * Kamailio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +/*! + * \file + * \brief Kamailio lost :: response + * \ingroup lost + * Module: \ref lost + */ + +#include +#include +#include +#include +#include + +#include "../../core/parser/msg_parser.h" +#include "../../core/parser/parse_content.h" +#include "../../core/parser/parse_uri.h" +#include "../../core/parser/parse_from.h" +#include "../../core/parser/parse_ppi_pai.h" +#include "../../core/dprint.h" +#include "../../core/mem/mem.h" +#include "../../core/mem/shm_mem.h" +#include "../../core/rand/kam_rand.h" + +#include +#include +#include +#include + +#include "pidf.h" +#include "utilities.h" +#include "response.h" + +/* return 1 if true else 0 */ +int is_http_laquot(char *search) +{ + if(search == NULL) { + return 0; + } + if(strlen(search) < strlen("category = OTHER; + res->mapping = NULL; + res->path = NULL; + res->warnings = NULL; + res->errors = NULL; + res->redirect = NULL; + res->uri = NULL; + + LM_DBG("### reponse data initialized\n"); + + return res; +} + +/* + * lost_new_response_type(void) + * creates a new response type object in private memory and returns a pointer + */ +p_type_t lost_new_response_type(void) +{ + p_type_t res; + + res = (p_type_t)pkg_malloc(sizeof(s_type_t)); + if(res == NULL) { + LM_ERR("no more private memory\n"); + return NULL; + } + res->type = NULL; + res->target = NULL; + res->source = NULL; + + res->info = (p_info_t)pkg_malloc(sizeof(s_info_t)); + if(res->info == NULL) { + LM_ERR("no more private memory\n"); + } else { + res->info->text = NULL; + res->info->lang = NULL; + } + + LM_DBG("### type data initialized\n"); + + return res; +} + +/* + * lost_new_response_issues(void) + * creates a new issues object in private memory and returns a pointer + */ +p_issue_t lost_new_response_issues(void) +{ + p_issue_t res = NULL; + + res = (p_issue_t)pkg_malloc(sizeof(s_issue_t)); + if(res == NULL) { + LM_ERR("no more private memory\n"); + return NULL; + } + res->issue = NULL; + res->next = NULL; + + LM_DBG("### issues data initialized\n"); + + return res; +} + +/* + * lost_new_response_data(void) + * creates a new response data object in private memory and returns a pointer + */ +p_data_t lost_new_response_data(void) +{ + p_data_t res; + + res = (p_data_t)pkg_malloc(sizeof(s_data_t)); + if(res == NULL) { + LM_ERR("no more private memory\n"); + return NULL; + } + res->expires = NULL; + res->updated = NULL; + res->source = NULL; + res->sourceid = NULL; + res->urn = NULL; + res->name = NULL; + res->number = NULL; + + LM_DBG("### mapping data initialized\n"); + + return res; +} + +/* + * lost_new_response_list(void) + * creates a new response list object in private memory and returns a pointer + */ +p_list_t lost_new_response_list(void) +{ + p_list_t list; + + list = (p_list_t)pkg_malloc(sizeof(s_list_t)); + if(list == NULL) { + LM_ERR("no more private memory\n"); + return NULL; + } + + list->value = NULL; + list->next = NULL; + + LM_DBG("### list data initialized\n"); + + return list; +} + +/* + * lost_reverse_response_list(list) + * reverses list order of a list object + */ +void lost_reverse_response_list(p_list_t *head) +{ + p_list_t prev = NULL; + p_list_t next = NULL; + p_list_t current = *head; + + while(current != NULL) { + next = current->next; + current->next = prev; + prev = current; + current = next; + } + *head = prev; +} + +/* + * lost_delete_response_list(list) + * removes response list from private memory + */ +void lost_delete_response_list(p_list_t list) +{ + p_list_t cur; + + while((cur = list) != NULL) { + list = cur->next; + if(cur->value != NULL) { + pkg_free(cur->value); + } + pkg_free(cur); + } + if(list != NULL) { + pkg_free(list); + list = NULL; + } + + LM_DBG("### list data deleted\n"); + + return; +} + +/* + * lost_delete_response_msg(msg) + * removes response info from private memory + */ +void lost_delete_response_info(p_info_t info) +{ + if(info->text != NULL) { + pkg_free(info->text); + } + if(info->lang != NULL) { + pkg_free(info->lang); + } + if(info != NULL) { + pkg_free(info); + } + + LM_DBG("### info data deleted\n"); + + return; +} + +/* + * lost_delete_response_msg(type) + * removes response type from private memory + */ +void lost_delete_response_type(p_type_t type) +{ + if(type->type != NULL) { + pkg_free(type->type); + } + if(type->target != NULL) { + pkg_free(type->target); + } + if(type->source != NULL) { + pkg_free(type->source); + } + if(type->info != NULL) { + lost_delete_response_info(type->info); + } + if(type != NULL) { + pkg_free(type); + type = NULL; + } + + LM_DBG("### type data deleted\n"); + + return; +} + +/* + * lost_delete_response_issue(list) + * removes response issue object from private memory + */ +void lost_delete_response_issues(p_issue_t list) +{ + p_issue_t cur; + + while((cur = list) != NULL) { + list = cur->next; + if(cur->issue != NULL) { + lost_delete_response_type(cur->issue); + } + pkg_free(cur); + } + if(list != NULL) { + pkg_free(list); + list = NULL; + } + + LM_DBG("### issue data deleted\n"); + + return; +} + +/* + * lost_delete_response_issue(mapping) + * removes respone data object from private memory + */ +void lost_delete_response_data(p_data_t m) +{ + if(m->expires != NULL) { + pkg_free(m->expires); + } + if(m->updated != NULL) { + pkg_free(m->updated); + } + if(m->source != NULL) { + pkg_free(m->source); + } + if(m->sourceid != NULL) { + pkg_free(m->sourceid); + } + if(m->urn != NULL) { + pkg_free(m->urn); + } + if(m->name != NULL) { + lost_delete_response_info(m->name); + } + if(m->number != NULL) { + pkg_free(m->number); + } + if(m != NULL) { + pkg_free(m); + m = NULL; + } + + LM_DBG("### mapping data deleted\n"); + + return; +} + +/* + * lost_delete_findServiceResponse(response) + * removes findServiceResponse object from private memory + */ +void lost_free_findServiceResponse(p_fsr_t res) +{ + if(res->mapping != NULL) { + lost_delete_response_data(res->mapping); + } + if(res->path != NULL) { + lost_delete_response_list(res->path); + } + if(res->warnings != NULL) { + lost_delete_response_issues(res->warnings); + } + if(res->errors != NULL) { + lost_delete_response_issues(res->errors); + } + if(res->redirect != NULL) { + lost_delete_response_type(res->redirect); + } + if(res->uri != NULL) { + lost_delete_response_list(res->uri); + } + if(res != NULL) { + pkg_free(res); + res = NULL; + } + + LM_DBG("### findServiceResponse deleted\n"); + + return; +} + +/* + * lost_get_response_issue(node) + * parses response issue (errors, warnings) and writes + * results to issue object + */ +p_issue_t lost_get_response_issues(xmlNodePtr node) +{ + xmlNodePtr cur = NULL; + + p_issue_t list = NULL; + p_issue_t new = NULL; + p_type_t issue = NULL; + + str tmp = STR_NULL; + + int len = 0; + + if(node == NULL) { + return NULL; + ; + } + + LM_DBG("### LOST\t%s\n", node->name); + + cur = node->children; + while(cur) { + if(cur->type == XML_ELEMENT_NODE) { + /* get a new list element */ + new = lost_new_response_issues(); + if(new == NULL) { + return NULL; + } + /* parse the element */ + issue = lost_new_response_type(); + if(issue == NULL) { + LM_ERR("no more private memory\n"); + pkg_free(list); + pkg_free(new); + return NULL; + } + issue->source = lost_get_property(cur->parent, MAPP_PROP_SRC, &len); + tmp.s = (char *)cur->name; + tmp.len = strlen((char *)cur->name); + if(tmp.len > 0 && tmp.s != NULL) { + issue->type = lost_copy_string(tmp, &len); + } + if(len > 0) { + + LM_DBG("###\t[%s]\n", issue->type); + + if(issue->info != NULL) { + issue->info->text = lost_get_property(cur, PROP_MSG, &len); + issue->info->lang = lost_get_property(cur, PROP_LANG, &len); + } + /* append to list */ + new->issue = issue; + new->next = list; + list = new; + } else { + lost_delete_response_issues(new); /* clean up */ + } + /* get next element */ + cur = cur->next; + } + } + + return list; +} + +/* + * lost_get_response_list(node, name, property) + * parses response list and writes results to list object + */ +p_list_t lost_get_response_list( + xmlNodePtr node, const char *name, const char *prop) +{ + xmlNodePtr cur = NULL; + + p_list_t list = NULL; + p_list_t new = NULL; + + str tmp = STR_NULL; + int len = 0; + + if(node == NULL) { + return list; + } + + LM_DBG("### LOST\t%s\n", node->name); + + for(cur = node; cur; cur = cur->next) { + if(cur->type == XML_ELEMENT_NODE) { + if(!xmlStrcasecmp(cur->name, (unsigned char *)name)) { + new = lost_new_response_list(); + if(new != NULL) { + if(prop) { + tmp.s = lost_get_property(cur, prop, &tmp.len); + } else { + tmp.s = lost_get_content(cur, name, &tmp.len); + } + if(tmp.len > 0 && tmp.s != NULL) { + new->value = lost_copy_string(tmp, &len); + + LM_DBG("###\t[%s]\n", new->value); + + new->next = list; + list = new; + lost_free_string(&tmp); /* clean up */ + } else { + lost_delete_response_list(new); /* clean up */ + } + } + } + } else { + /* not an uri element */ + break; + } + } + + return list; +} + +/* + * lost_get_response_element(node, name) + * parses response element and returns a char pointer + */ +char *lost_get_response_element(xmlNodePtr node, const char *name) +{ + char *ret = NULL; + int len = 0; + + if(node == NULL) { + return ret; + } + + LM_DBG("### LOST %s\n", node->name); + + ret = lost_get_content(node, name, &len); + + LM_DBG("###\t[%.*s]\n", len, ret); + + return ret; +} + +/* + * lost_get_response_type(node, name) + * parses response type and writes results to type object + */ +p_type_t lost_get_response_type(xmlNodePtr node, const char *name) +{ + p_type_t res = NULL; + + str tmp = STR_NULL; + + int len = 0; + + if(node == NULL) { + return res; + } + + LM_DBG("### LOST %s\n", node->name); + + tmp.s = lost_get_childname(node, name, &tmp.len); + if(tmp.len > 0 && tmp.s != NULL) { + res = lost_new_response_type(); + if(res != NULL) { + res->type = lost_copy_string(tmp, &len); + if(len > 0) { + + LM_DBG("###\t[%s]\n", res->type); + } + if(res->info != NULL) { + res->info->text = + lost_get_property(node->children, PROP_MSG, &len); + res->info->lang = + lost_get_property(node->children, PROP_LANG, &len); + } + } + lost_free_string(&tmp); /* clean up */ + } + + return res; +} + +/* + * lost_get_response_info(node, name, property) + * parses response info (text, language) and writes results to info object + */ +p_info_t lost_get_response_info( + xmlNodePtr node, const char *name, const char *prop) +{ + p_info_t res = NULL; + + str tmp = STR_NULL; + + int len = 0; + + if(node == NULL) { + return res; + } + + LM_DBG("### LOST %s\n", node->name); + + res = (p_info_t)pkg_malloc(sizeof(s_info_t)); + if(res == NULL) { + LM_ERR("no more private memory\n"); + return NULL; + } else { + res->text = NULL; + res->lang = NULL; + if(prop) { + tmp.s = lost_get_property(node, PROP_MSG, &tmp.len); + } else { + tmp.s = lost_get_content(node, name, &tmp.len); + } + if(tmp.len > 0 && tmp.s != NULL) { + res->text = lost_copy_string(tmp, &len); + if(len > 0) { + + LM_DBG("###\t\t[%s]\n", res->text); + } + lost_free_string(&tmp); /* clean up */ + } + res->lang = lost_get_property(node, PROP_LANG, &len); + + LM_DBG("###\t\t[%s]\n", res->lang); + } + + return res; +} + +/* + * lost_print_findServiceResponse(response) + * prints/logs response elements + */ +void lost_print_findServiceResponse(p_fsr_t res) +{ + if(res == NULL) { + return; + } + p_data_t m = NULL; + p_type_t r = NULL; + p_issue_t e = NULL; + p_issue_t w = NULL; + p_type_t t = NULL; + p_list_t list = NULL; + + switch(res->category) { + case RESPONSE: + if((m = res->mapping) != NULL) { + LM_INFO("### LOST %s:\t[%s]\n", MAPP_PROP_EXP, m->expires); + LM_INFO("### LOST %s:\t[%s]\n", MAPP_PROP_LUP, m->updated); + LM_INFO("### LOST %s:\t[%s]\n", MAPP_PROP_SRC, m->source); + LM_INFO("### LOST %s:\t[%s]\n", MAPP_PROP_SID, m->sourceid); + if(m->name) { + LM_INFO("### LOST %s:\t[%s (%s)]\n", DISPNAME_NODE, + m->name->text, m->name->lang); + } + LM_INFO("### LOST %s:\t[%s]\n", SERVICENR_NODE, m->number); + LM_INFO("### LOST %s:\t[%s]\n", SERVICE_NODE, m->urn); + if((list = res->uri) != NULL) { + while(list) { + LM_INFO("### LOST %s:\t[%s]\n", MAPP_NODE_URI, + list->value); + list = list->next; + } + } + if((list = res->path) != NULL) { + while(list) { + LM_INFO("### LOST %s:\t[%s]\n", PATH_NODE_VIA, + list->value); + list = list->next; + } + } + if((w = res->warnings) != NULL) { + while(w) { + t = w->issue; + LM_INFO("###! LOST %s reported ...\n", t->source); + LM_INFO("###! LOST %s:\n", t->type); + if(t->info) { + LM_INFO("###! LOST\t[%s (%s)]\n", t->info->text, + t->info->lang); + } + w = w->next; + } + } + } + break; + case REDIRECT: + if((r = res->redirect) != NULL) { + LM_INFO("### LOST %s:\t[%s]\n", RED_PROP_TAR, r->target); + LM_INFO("### LOST %s:\t[%s]\n", RED_PROP_SRC, r->source); + if(r->info) { + LM_INFO("### LOST %s:\t[%s (%s)]\n", PROP_MSG, + r->info->text, r->info->lang); + } + } + break; + case ERROR: + if((e = res->errors) != NULL) { + while(e) { + t = e->issue; + LM_INFO("###! LOST %s reported ...\n", t->source); + LM_INFO("###! LOST %s:\n", t->type); + if(t->info) { + LM_INFO("###! LOST\t[%s (%s)]\n", t->info->text, + t->info->lang); + } + e = e->next; + } + } + break; + case OTHER: + default: + break; + } + + return; +} + +/* + * lost_parse_findServiceResponse(str) + * read and parse the findServiceResponse xml string + */ +p_fsr_t lost_parse_findServiceResponse(str ret) +{ + xmlDocPtr doc = NULL; + xmlNodePtr root = NULL; + xmlNodePtr node = NULL; + + p_fsr_t res = NULL; + p_data_t m = NULL; + p_type_t r = NULL; + + int len = 0; + + doc = xmlReadMemory(ret.s, ret.len, 0, 0, + XML_PARSE_NOBLANKS | XML_PARSE_NONET | XML_PARSE_NOCDATA); + + if(doc == NULL) { + LM_ERR("invalid xml document: [%.*s]\n", ret.len, ret.s); + doc = xmlRecoverMemory(ret.s, ret.len); + if(doc == NULL) { + LM_ERR("xml document recovery failed on: [%.*s]\n", ret.len, ret.s); + return NULL; + } + + LM_DBG("xml document recovered\n"); + } + root = xmlDocGetRootElement(doc); + if(root == NULL) { + LM_ERR("empty xml document: [%.*s]\n", ret.len, ret.s); + xmlFreeDoc(doc); /* clean up */ + return NULL; + } + + LM_DBG("### %s received\n", root->name); + + res = lost_new_response(); + if(res == NULL) { + LM_ERR("no more private memory\n"); + xmlFreeDoc(doc); /* clean up */ + return NULL; + } + /* check the root element ... */ + /* findServiceResponse */ + if(!xmlStrcmp(root->name, (unsigned char *)ROOT_NODE)) { + m = lost_new_response_data(); + if(m == NULL) { + LM_ERR("no more private memory\n"); + /* clean up */ + xmlFreeDoc(doc); + lost_free_findServiceResponse(res); + return NULL; + } + /* get mapping properties */ + node = xmlDocGetNodeByName(doc, MAPP_NODE, NULL); + m->expires = lost_get_property(node, MAPP_PROP_EXP, &len); + m->updated = lost_get_property(node, MAPP_PROP_LUP, &len); + m->source = lost_get_property(node, MAPP_PROP_SRC, &len); + m->sourceid = lost_get_property(node, MAPP_PROP_SID, &len); + node = NULL; + /* get the displayName element */ + node = xmlDocGetNodeByName(doc, DISPNAME_NODE, NULL); + m->name = lost_get_response_info(node, DISPNAME_NODE, NULL); + /* get the serviceNumber element */ + m->number = lost_get_response_element(root, SERVICENR_NODE); + /* get the service element */ + m->urn = lost_get_response_element(root, SERVICE_NODE); + node = NULL; + /* get the via path (list) */ + node = xmlDocGetNodeByName(doc, PATH_NODE_VIA, NULL); + res->path = lost_get_response_list(node, PATH_NODE_VIA, MAPP_PROP_SRC); + lost_reverse_response_list(&res->path); + node = NULL; + /* get the uri element list */ + node = xmlDocGetNodeByName(doc, MAPP_NODE_URI, NULL); + res->uri = lost_get_response_list(node, MAPP_NODE_URI, NULL); + lost_reverse_response_list(&res->uri); + node = NULL; + /* get the warnings element */ + node = xmlDocGetNodeByName(doc, WARNINGS_NODE, NULL); + res->warnings = lost_get_response_issues(node); + /* return */ + res->mapping = m; + res->category = RESPONSE; + /* check the root element ... */ + /* errors */ + } else if(!xmlStrcmp(root->name, (unsigned char *)ERRORS_NODE)) { + res->errors = lost_get_response_issues(root); + /* return */ + res->category = ERROR; + /* check the root element ... */ + /* redirect */ + } else if(!xmlStrcmp(root->name, (unsigned char *)RED_NODE)) { + r = lost_new_response_type(); + if(r == NULL) { + LM_ERR("no more private memory\n"); + xmlFreeDoc(doc); /* clean up */ + lost_free_findServiceResponse(res); + return NULL; + } + r->source = lost_get_property(root, RED_PROP_SRC, &len); + r->target = lost_get_property(root, RED_PROP_TAR, &len); + if(r->info != NULL) { + r->info->text = lost_get_property(root, RED_PROP_MSG, &len); + r->info->lang = lost_get_property(root, PROP_LANG, &len); + } + /* return */ + res->redirect = r; + res->category = REDIRECT; + /* check the root element ... */ + /* unknown */ + } else { + LM_ERR("root element is not valid: [%.*s]\n", ret.len, ret.s); + res->category = OTHER; + } + + xmlFreeDoc(doc); /* clean up */ + + return res; +} \ No newline at end of file diff --git a/src/modules/lost/response.h b/src/modules/lost/response.h new file mode 100644 index 00000000000..59b76ee488c --- /dev/null +++ b/src/modules/lost/response.h @@ -0,0 +1,131 @@ +/* + * lost module LoST response parsing functions + * + * Copyright (C) 2021 Wolfgang Kampichler + * DEC112, FREQUENTIS AG + * + * This file is part of Kamailio, a free SIP server. + * + * Kamailio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * Kamailio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +/*! + * \file + * \brief Kamailio lost :: response + * \ingroup lost + * Module: \ref lost + */ + +#ifndef LOST_RESPONSE_H +#define LOST_RESPONSE_H + +#define PROP_LANG (const char *)"lang" +#define PROP_MSG (const char *)"message" + +#define ROOT_NODE (const char *)"findServiceResponse" +#define DISPNAME_NODE (const char *)"displayName" +#define SERVICE_NODE (const char *)"service" +#define SERVICENR_NODE (const char *)"serviceNumber" +#define WARNINGS_NODE (const char *)"warnings" +#define PATH_NODE (const char *)"via" +#define PATH_NODE_VIA (const char *)"via" +#define MAPP_NODE (const char *)"mapping" +#define MAPP_NODE_URI (const char *)"uri" +#define MAPP_PROP_EXP (const char *)"expires" +#define MAPP_PROP_LUP (const char *)"lastUpdated" +#define MAPP_PROP_SRC (const char *)"source" +#define MAPP_PROP_SID (const char *)"sourceId" + +#define RED_NODE (const char *)"redirect" +#define RED_PROP_TAR (const char *)"target" +#define RED_PROP_SRC (const char *)"source" +#define RED_PROP_MSG (const char *)"message" + +#define ERRORS_NODE (const char *)"errors" + +typedef struct LIST +{ + char *value; + struct LIST *next; +} s_list_t, *p_list_t; + +typedef struct INFO +{ + char *text; + char *lang; +} s_info_t, *p_info_t; + +typedef struct DATA +{ + char *expires; + char *updated; + char *source; + char *sourceid; + char *urn; + char *number; + p_info_t name; +} s_data_t, *p_data_t; + +typedef struct TYPE +{ + char *type; + char *target; + char *source; + p_info_t info; +} s_type_t, *p_type_t; + +typedef struct ISSUE +{ + p_type_t issue; + struct ISSUE *next; +} s_issue_t, *p_issue_t; + +typedef enum CAT +{ + RESPONSE, + ERROR, + REDIRECT, + OTHER = -1 +} cat_t; + +typedef struct FSR +{ + cat_t category; + p_data_t mapping; + p_issue_t warnings; + p_issue_t errors; + p_type_t redirect; + p_list_t path; + p_list_t uri; +} s_fsr_t, *p_fsr_t; + +/* read and parse response data */ +p_fsr_t lost_parse_findServiceResponse(str); +/* print the response */ +void lost_print_findServiceResponse(p_fsr_t); +/* remove response data from memory */ +void lost_free_findServiceResponse(p_fsr_t); + +/* uri scheme parsing */ +int is_urn(char *); +int is_cid(char *); +int is_http(char *); +int is_https(char *); +int is_cid_laquot(char *); +int is_http_laquot(char *); +int is_https_laquot(char *); + +#endif diff --git a/src/modules/lost/utilities.c b/src/modules/lost/utilities.c index fca503cbf65..628211bfb86 100644 --- a/src/modules/lost/utilities.c +++ b/src/modules/lost/utilities.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "../../core/parser/msg_parser.h" #include "../../core/parser/parse_content.h" @@ -56,6 +57,11 @@ char *lost_trim_content(char *str, int *lgth) { char *end; + *lgth = 0; + + if(str == NULL) + return NULL; + while(isspace(*str)) str++; @@ -199,8 +205,13 @@ p_held_t lost_new_held(str s_uri, str s_type, int time, int exact) */ void lost_free_loc(p_loc_t ptr) { - pkg_free(ptr->identity); - pkg_free(ptr->urn); + if(ptr == NULL) + return; + + if(ptr->identity) + pkg_free(ptr->identity); + if(ptr->urn) + pkg_free(ptr->urn); if(ptr->xpath) pkg_free(ptr->xpath); if(ptr->geodetic) @@ -212,7 +223,9 @@ void lost_free_loc(p_loc_t ptr) if(ptr->profile) pkg_free(ptr->profile); - pkg_free(ptr); + if(ptr) + pkg_free(ptr); + ptr = NULL; } @@ -222,22 +235,55 @@ void lost_free_loc(p_loc_t ptr) */ void lost_free_held(p_held_t ptr) { - pkg_free(ptr->identity); - pkg_free(ptr->type); + if(ptr == NULL) + return; + + if(ptr->identity) + pkg_free(ptr->identity); + if(ptr->type) + pkg_free(ptr->type); pkg_free(ptr); ptr = NULL; } +/* + * lost_copy_string(str, int*) { + * copies a string and returns string allocated in private memory + */ +char *lost_copy_string(str src, int *lgth) +{ + char *res = NULL; + + if(src.s == NULL && src.len == 0) { + *lgth = 0; + return NULL; + } + res = (char *)pkg_malloc((src.len + 1) * sizeof(char)); + if(res == NULL) { + LM_ERR("no more private memory\n"); + *lgth = 0; + } else { + memset(res, 0, src.len + 1); + memcpy(res, src.s, src.len + 1); + res[src.len] = '\0'; + *lgth = (int)strlen(res); + } + + return res; +} + /* * lost_free_string(ptr) * frees and resets a string */ void lost_free_string(str *string) { - str ptr = *string; + if(string == NULL) + return; - if(ptr.s) { + str ptr = *string; + if(ptr.s != NULL && ptr.len > 0) { pkg_free(ptr.s); ptr.s = NULL; ptr.len = 0; @@ -246,12 +292,14 @@ void lost_free_string(str *string) /* * lost_get_content(node, name, lgth) - * gets a nodes "name" content and returns string allocated in private memory + * gets a nodes "name" content, removes whitespace and returns string + * allocated in private memory */ char *lost_get_content(xmlNodePtr node, const char *name, int *lgth) { xmlNodePtr cur = node; char *content = NULL; + char *trimmed = NULL; char *cnt = NULL; int len; @@ -262,7 +310,7 @@ char *lost_get_content(xmlNodePtr node, const char *name, int *lgth) LM_ERR("could not get XML node content\n"); return cnt; } else { - len = strlen(content); + trimmed = lost_trim_content(content, &len); cnt = (char *)pkg_malloc((len + 1) * sizeof(char)); if(cnt == NULL) { LM_ERR("no more private memory\n"); @@ -270,7 +318,7 @@ char *lost_get_content(xmlNodePtr node, const char *name, int *lgth) return cnt; } memset(cnt, 0, len + 1); - memcpy(cnt, content, len); + memcpy(cnt, trimmed, len); cnt[len] = '\0'; } @@ -325,7 +373,10 @@ char *lost_get_childname(xmlNodePtr node, const char *name, int *lgth) xmlNodePtr cur = node; xmlNodePtr parent = NULL; xmlNodePtr child = NULL; + char *cnt = NULL; + char *trimmed = NULL; + int len; *lgth = 0; @@ -335,22 +386,19 @@ char *lost_get_childname(xmlNodePtr node, const char *name, int *lgth) LM_ERR("xmlNodeGetNodeByName() failed\n"); return cnt; } - child = parent->children; if(child == NULL) { LM_ERR("%s has no children '%s'\n", parent->name, name); return cnt; } - - len = strlen((char *)child->name); + trimmed = lost_trim_content((char *)child->name, &len); cnt = (char *)pkg_malloc((len + 1) * sizeof(char)); if(cnt == NULL) { LM_ERR("no more private memory\n"); return cnt; } - memset(cnt, 0, len + 1); - memcpy(cnt, child->name, len); + memcpy(cnt, trimmed, len); cnt[len] = '\0'; *lgth = strlen(cnt); @@ -359,49 +407,31 @@ char *lost_get_childname(xmlNodePtr node, const char *name, int *lgth) } /* - * lost_get_geolocation_header(msg, lgth) - * gets the Geolocation header value and returns string allocated in - * private memory + * lost_get_geolocation_header(msg, hdr) + * gets the Geolocation header value and returns 1 on success */ -char *lost_get_geolocation_header(struct sip_msg *msg, int *lgth) +int lost_get_geolocation_header(struct sip_msg *msg, str *hdr) { struct hdr_field *hf; - char *res = NULL; - - *lgth = 0; if(parse_headers(msg, HDR_EOH_F, 0) == -1) { LM_ERR("failed to parse geolocation header\n"); - return res; + return 0; } - for(hf = msg->headers; hf; hf = hf->next) { if((hf->type == HDR_OTHER_T) && (hf->name.len == LOST_GEOLOC_HEADER_SIZE - 2)) { /* possible hit */ - if(strncasecmp(hf->name.s, LOST_GEOLOC_HEADER, - LOST_GEOLOC_HEADER_SIZE) == 0) { - - res = (char *)pkg_malloc((hf->body.len + 1) * sizeof(char)); - if(res == NULL) { - LM_ERR("no more private memory\n"); - return res; - } else { - memset(res, 0, hf->body.len + 1); - memcpy(res, hf->body.s, hf->body.len + 1); - res[hf->body.len] = '\0'; - - *lgth = strlen(res); - } - } else { - LM_ERR("header '%.*s' length %d\n", hf->body.len, hf->body.s, - hf->body.len); + if(strncasecmp( + hf->name.s, LOST_GEOLOC_HEADER, LOST_GEOLOC_HEADER_SIZE) + == 0) { + hdr->s = hf->body.s; + hdr->len = hf->body.len; + return 1; } - break; } } - - return res; + return 0; } /* @@ -426,8 +456,8 @@ char *lost_get_pai_header(struct sip_msg *msg, int *lgth) if((hf->type == HDR_PAI_T) && (hf->name.len == LOST_PAI_HEADER_SIZE - 2)) { /* possible hit */ - if(strncasecmp(hf->name.s, LOST_PAI_HEADER, - LOST_PAI_HEADER_SIZE) == 0) { + if(strncasecmp(hf->name.s, LOST_PAI_HEADER, LOST_PAI_HEADER_SIZE) + == 0) { LM_DBG("P-A-I body: [%.*s]\n", hf->body.len, hf->body.s); @@ -472,6 +502,99 @@ char *lost_get_pai_header(struct sip_msg *msg, int *lgth) return res; } +/* + * lost_parse_host(uri, string) + * parses host (ipv4, ipv6 or name) from uri and returns string + */ +int lost_parse_host(const char *uri, str *host, int *flag) +{ + char *search = (char *)uri; + char *end; + + int len = 0; + int ip6 = 0; + + while((len < strlen(uri)) && (*search++ != '@')) { + len++; + } + + if(len == strlen(uri)) { + return 0; + } + + if(*(search) == 0) + return 0; + + if(*(search) == '[') { + ip6 = 1; + } + + end = search; + + if(ip6) { + while((len < strlen(uri)) && (*end++ != ']')) { + len++; + } + if(len == strlen(uri)) { + return 0; + } + } else { + while(len < strlen(uri)) { + if((*end == ':') || (*end == '>')) { + break; + } + end++; + len++; + } + } + + if(*(search) == 0) + return 0; + + host->s = search; + host->len = end - search; + + if(ip6) { + *flag = AF_INET; + } else { + *flag = AF_INET; + } + + return 1; +} + +int lost_get_nameinfo(char *ip, str *name, int flag) +{ + struct sockaddr_in sa4; + struct sockaddr_in6 sa6; + + if(flag == AF_INET) { + bzero(&sa4, sizeof(sa4)); + sa4.sin_family = flag; + if(inet_pton(flag, ip, &sa4.sin_addr) <= 0) + return 0; + if(getnameinfo((struct sockaddr *)&sa4, sizeof(sa4), name->s, name->len, + NULL, 0, NI_NAMEREQD)) + return 0; + + return 1; + } + + if(flag == AF_INET6) { + bzero(&sa6, sizeof(sa6)); + sa6.sin6_family = flag; + if(inet_pton(flag, ip, &sa6.sin6_addr) <= 0) + return 0; + if(getnameinfo((struct sockaddr *)&sa6, sizeof(sa6), name->s, name->len, + NULL, 0, NI_NAMEREQD)) + return 0; + + return 1; + } + + return 0; +} + /* * lost_get_from_header(msg, lgth) * gets the From header value and returns string allocated in @@ -518,7 +641,6 @@ char *lost_get_from_header(struct sip_msg *msg, int *lgth) */ void lost_delete_geoheader_list(p_geolist_t list) { - p_geolist_t curr; while((curr = list) != NULL) { @@ -543,7 +665,6 @@ void lost_delete_geoheader_list(p_geolist_t list) */ char *lost_get_geoheader_value(p_geolist_t list, geotype_t type, int *rtype) { - p_geolist_t head = list; char *value = NULL; @@ -570,14 +691,12 @@ char *lost_get_geoheader_value(p_geolist_t list, geotype_t type, int *rtype) return value; } - /* * lost_reverse_geoheader_list(list) * reverses list order */ void lost_reverse_geoheader_list(p_geolist_t *head) { - p_geolist_t prev = NULL; p_geolist_t next = NULL; p_geolist_t current = *head; @@ -598,7 +717,6 @@ void lost_reverse_geoheader_list(p_geolist_t *head) */ char *lost_copy_geoheader_value(char *src, int len) { - char *res = NULL; res = (char *)pkg_malloc((len + 1) * sizeof(char)); @@ -621,7 +739,6 @@ char *lost_copy_geoheader_value(char *src, int len) */ p_geolist_t lost_new_geoheader_list(str hdr, int *items) { - char *search = NULL; char *cidptr = NULL; char *urlptr = NULL; @@ -790,8 +907,7 @@ p_loc_t lost_parse_pidf(str pidf, str urn) pidf.len, pidf.s); goto err; } - - /* free memory */ + /* clean up */ xmlFreeDoc(doc); doc = NULL; @@ -799,7 +915,7 @@ p_loc_t lost_parse_pidf(str pidf, str urn) err: LM_ERR("pidflo parsing error\n"); - /* free memory */ + /* clean up */ if(doc != NULL) { xmlFreeDoc(doc); doc = NULL; @@ -1048,7 +1164,7 @@ int lost_xpath_location(xmlDocPtr doc, char *path, p_loc_t loc) } memset(loc->xpath, 0, len + 1); memcpy(loc->xpath, tmp, len); - /* free memory */ + /* clean up */ pkg_free(ptr); ptr = NULL; } else { @@ -1078,7 +1194,6 @@ int lost_xpath_location(xmlDocPtr doc, char *path, p_loc_t loc) */ int lost_parse_location_info(xmlNodePtr root, p_loc_t loc) { - if(lost_xpath_location(root->doc, LOST_XPATH_GP, loc) == 0) { return 0; } diff --git a/src/modules/lost/utilities.h b/src/modules/lost/utilities.h index a77bd83af18..04a24844551 100644 --- a/src/modules/lost/utilities.h +++ b/src/modules/lost/utilities.h @@ -121,18 +121,21 @@ void lost_delete_geoheader_list(p_geolist_t); int lost_parse_location_info(xmlNodePtr, p_loc_t); int lost_xpath_location(xmlDocPtr, char *, p_loc_t); int lost_parse_geo(xmlNodePtr, p_loc_t); +int lost_parse_host(const char *, str *, int *); +int lost_get_geolocation_header(struct sip_msg *, str *); +int lost_get_nameinfo(char *, str *, int); char *lost_find_service_request(p_loc_t, int *); char *lost_held_location_request(p_held_t, int *); char *lost_get_content(xmlNodePtr, const char *, int *); char *lost_get_property(xmlNodePtr, const char *, int *); -char *lost_get_geolocation_header(struct sip_msg *, int *); char *lost_get_from_header(struct sip_msg *, int *); char *lost_get_pai_header(struct sip_msg *, int *); char *lost_get_childname(xmlNodePtr, const char *, int *); char *lost_trim_content(char *, int *); char *lost_copy_geoheader_value(char *, int); char *lost_get_geoheader_value(p_geolist_t, geotype_t, int *); +char *lost_copy_string(str, int *); p_loc_t lost_new_loc(str); p_loc_t lost_parse_pidf(str, str); diff --git a/utils/kamctl/kamctl b/utils/kamctl/kamctl deleted file mode 100755 index 338b4a85857..00000000000 --- a/utils/kamctl/kamctl +++ /dev/null @@ -1,3202 +0,0 @@ -#!/bin/sh -# -# control tool for maintaining Kamailio -# -#=================================================================== - -### version for this script -VERSION='5.4.0' - -PATH=$PATH:/usr/local/sbin/ - -# for testing only, please don't enable this in production environments -# as this introduce security risks -if [ -z "$KAMCTL_TEST" ]; then - TEST="false" -else - TEST="true" -fi - -### include config files - -# check for rc file at same location with kamctl -which greadlink >/dev/null 2>&1 -ret=$? -if [ $ret -eq 0 ] ; then - KAMCTLFULLPATH=$(greadlink -f "$0") -else - which readlink >/dev/null 2>&1 - ret=$? - if [ $ret -eq 0 ] ; then - KAMCTLFULLPATH=$(readlink -f "$0") - fi -fi -if [ -n "$KAMCTLFULLPATH" ] ; then - KAMCTLDIRPATH=$(dirname "$KAMCTLFULLPATH") - if [ -f $KAMCTLDIRPATH/kamctlrc ]; then - . $KAMCTLDIRPATH/kamctlrc - fi -fi - -# check for rc file at standard locations -if [ -f /etc/kamailio/kamctlrc ]; then - . /etc/kamailio/kamctlrc -fi -if [ -f /usr/local/etc/kamailio/kamctlrc ]; then - . /usr/local/etc/kamailio/kamctlrc -fi -if [ -f ~/.kamctlrc ]; then - . ~/.kamctlrc -fi - -if [ $TEST = "true" ]; then - if [ -f ./kamctlrc ]; then - . ./kamctlrc - fi -fi - - -### force values for variables in this section -# you better set the variables in ~/.kamctlrc -if [ -z "$ETCDIR" ] ; then - ETCDIR="/usr/local/etc/kamailio" -fi - -if [ -z "$MYDIR" ] ; then - MYDIR=`dirname $0` -fi - -if [ -z "$MYLIBDIR" ] ; then - MYLIBDIR="/usr/local/lib/kamailio/kamctl" - if [ ! -d "$MYLIBDIR" ]; then - MYLIBDIR=$MYDIR - fi -fi - -##### ------------------------------------------------ ##### -### load base functions -# -if [ -f "$MYLIBDIR/kamctl.base" ]; then - . "$MYLIBDIR/kamctl.base" -else - echo -e "Cannot load core functions '$MYLIBDIR/kamctl.base' - exiting ...\n" - exit -1 -fi - -# locate kamcmd -if [ -z "$SERCMD" ] ; then - # try same dir as kamctl - SERCMD="$MYDIR/kamcmd" - if [ ! -f "$SERCMD" -o ! -x "$SERCMD" ] ; then - # try standard location installed from sources - SERCMD="/usr/local/sbin/kamcmd" - if [ ! -f "$SERCMD" -o ! -x "$SERCMD" ] ; then - # try source tree location - SERCMD="$MYDIR/../sercmd/kamcmd" - if [ ! -f "$SERCMD" -o ! -x "$SERCMD" ] ; then - # try locate it with which - SERCMD=`which kamcmd` - if [ ! -f "$SERCMD" -o ! -x "$SERCMD" ] ; then - mdbg "kamcmd tool not found" - fi - fi - fi - fi -else - if [ ! -f "$SERCMD" -o ! -x "$SERCMD" ] ; then - merr "SERCMD does not point to an executable file" - exit -1; - fi -fi - -# -##### ------------------------------------------------ ##### -### DBENGINE -# -DBENGINELOADED=0 -case $DBENGINE in - MYSQL|mysql|MySQL) - if [ -f "$MYLIBDIR/kamctl.mysql" ]; then - . "$MYLIBDIR/kamctl.mysql" - DBENGINELOADED=1 - fi - ;; - PGSQL|pgsql|postgres|postgresql|POSTGRESQL) - if [ -f "$MYLIBDIR/kamctl.pgsql" ]; then - . "$MYLIBDIR/kamctl.pgsql" - DBENGINELOADED=1 - fi - ;; - ORACLE|oracle|Oracle) - if [ -f "$MYLIBDIR/kamctl.oracle" ]; then - . "$MYLIBDIR/kamctl.oracle" - DBENGINELOADED=1 - fi - ;; - - DBTEXT|dbtext|textdb) - if [ -f "$MYLIBDIR/kamctl.dbtext" ]; then - . "$MYLIBDIR/kamctl.dbtext" - DBENGINELOADED=1 - fi - ;; - DB_BERKELEY|db_berkeley|BERKELEY|berkeley) - if [ -f "$MYLIBDIR/kamctl.db_berkeley" ]; then - . "$MYLIBDIR/kamctl.db_berkeley" - DBENGINELOADED=1 - fi - ;; - SQLITE|sqlite) - if [ -f "$MYLIBDIR/kamctl.sqlite" ]; then - . "$MYLIBDIR/kamctl.sqlite" - DBENGINELOADED=1 - fi - ;; - -esac - -if [ $DBENGINELOADED -eq 1 ] ; then - mdbg "database engine '$DBENGINE' loaded" -elif [ -n "$DBENGINE" ] ; then - mwarn "database engine not found - tried '$DBENGINE'" -fi - -# -##### ------------------------------------------------ ##### -### CTLENGINE -# - -require_kamcmd() { - if [ -z "$SERCMD" ] ; then - merr "kamcmd tool is missing" - exit -1 - fi -} - -CTLENGINELOADED=0 -CTLENGINETYPE=0 - -if [ -z "$CTLENGINE" ] ; then - CTLENGINE="RPCFIFO" -fi -case $CTLENGINE in - RPCFIFO|rpcfifo) - if [ -f "$MYLIBDIR/kamctl.rpcfifo" ]; then - . "$MYLIBDIR/kamctl.rpcfifo" - CTLENGINELOADED=1 - CTLENGINETYPE=1 - fi - ;; -esac - -#### ------------------------------------------------- ##### -### Load kamcmd interface -# -if [ -f "$MYLIBDIR/kamctl.ser" ]; then - . "$MYLIBDIR/kamctl.ser" -fi - -if [ $CTLENGINELOADED -eq 1 ] ; then - mdbg "Control engine '$CTLENGINE' loaded" -else - mwarn "no control engine found - tried '$CTLENGINE'" -fi - -# -##### ------------------------------------------------ ##### -### common functions -# -usage() { - CMD=`basename $0` - if [ "0$VERIFY_ACL" -eq 1 ] ; then - EXTRA_TEXT="ACL privileges are: $ACL_GROUPS" - fi - cat < /dev/null - if [ $? -ne 0 ] ; then - echo "$RES" | $EGREP "^400" > /dev/null - if [ $? -eq 0 ] ; then - merr "400; check if you use aliases in Kamailio" - exit 1 - fi - echo "$RES" | $EGREP "^200" > /dev/null - if [ $? -eq 0 ] ; then - ALIAS_UL_EXISTS=1 - fi - # other errors - merr "$RES" - exit 1 - fi -} - -check_db_alias() { - require_dbengine - - ALIAS_DB_EXISTS=0 - - QUERY="select count(*) from $DA_TABLE where $DA_ALIAS_USER_COLUMN='$1' \ -and $DA_ALIAS_DOMAIN_COLUMN='$2';" - CNT=`$DBROCMD "$QUERY" | $EGREP -v ERROR | $LAST_LINE` - mdbg "check_db_alias: alias counter=$CNT" - if [ "$CNT" = "0" ] ; then - ALIAS_DB_EXISTS=0 - else - ALIAS_DB_EXISTS=1 - fi -} - -# -# check for alias duplicates -# params: user domain -# output: false if exists, true otherwise -check_alias() { - ALIAS_EXISTS=0 - - if [ "$ENABLE_ALIASES" = "1" ] ; then - check_ul_alias "$1" "$2" - if [ "$ALIAS_UL_EXISTS" = "0" ] ; then - ALIAS_EXISTS=0 - else - ALIAS_EXISTS=1 - fi - elif [ "$ENABLE_ALIASES" = "2" ] ; then - check_db_alias "$1" "$2" - if [ "$ALIAS_DB_EXISTS" = "0" ] ; then - ALIAS_EXISTS=0 - else - ALIAS_EXISTS=1 - fi - fi -} - -# db-based aliases -alias_db() { - if [ "$#" -lt 2 ] ; then - merr "alias_db - too few parameters" - echo - usage_alias_db - exit 1 - fi - - require_dbengine - - shift - - case $1 in - list) - if [ $# -eq 2 ] ; then - # print aliases for user - check_aor "$2" - if [ "$?" -ne "0" ] ; then - merr "alias_db - <$2> is not a valid AoR (user@domain)" - exit 1 - fi - - set_user $2 - - CLAUSE="WHERE $DA_USER_COLUMN='$OSERUSER' AND \ -$DA_DOMAIN_COLUMN='$OSERDOMAIN'" - mecho "Dumping aliases for user=<$2>" - echo - QUERY="SELECT CONCAT($DA_ALIAS_USER_COLUMN,\ -'@',$DA_ALIAS_DOMAIN_COLUMN) AS ALIAS FROM $DA_TABLE $CLAUSE;" - $DBROCMD "$QUERY" - # | $AWK 'BEGIN {line=0;} - # /^\+/ { next } - # { if(line==0) print "ALIASES"; - # else print line ")\t" $1 "@" $2; - # line++; }' - elif [ $# -eq 1 ] ; then - mecho "Dumping all aliases may take long: do you want to proceed? [Y|N] " - read answer - if [ "$answer" = "y" -o "$answer" = "Y" ] ; then - mecho "Dumping all aliases..." - echo - else - exit 1 - fi - QUERY="SELECT $DA_ALIAS_USER_COLUMN, $DA_ALIAS_DOMAIN_COLUMN,\ -$DA_USER_COLUMN, $DA_DOMAIN_COLUMN FROM $DA_TABLE;" - $DBROCMD "$QUERY" - # | $AWK 'BEGIN {line=0;} - # /^\+/ { next } - # { line++; - # if(line==1) print "SIP-ID \tALIAS\n"; - # else print $3 "@" $4 "\t" $1 "@" $2 }' - else - merr "alias_db - wrong number of params for command [list]" - echo - usage_alias_db - exit 1 - fi - - exit $? - ;; - show) - if [ $# -ne 2 ] ; then - merr "alias_db - wrong number of params for command [show]" - usage_alias_db - exit 1 - fi - - check_aor "$2" - if [ "$?" -ne "0" ] ; then - merr "alias_db - $2 is not a valid AoR (user@domain)" - exit 1 - fi - - set_user $2 - - CLAUSE="WHERE $DA_ALIAS_USER_COLUMN='$OSERUSER' AND \ -$DA_ALIAS_DOMAIN_COLUMN='$OSERDOMAIN'" - QUERY="SELECT CONCAT($DA_USER_COLUMN,'@',$DA_DOMAIN_COLUMN) \ -AS 'SIP-ID' FROM $DA_TABLE $CLAUSE ; " - $DBROCMD "$QUERY" - #TMP_UUID=`sql_ro_query "$QUERY" | $AWK 'BEGIN {line=0;} - # /^\+/ { next } - # { line++; - # if(line==2) print $1 "@" $2;}'` - # - #if [ "$TMP_UUID" = "" ] ; then - # mecho "non-existent alias <$2>" - # exit 1 - #fi - # - #echo "Details for alias <$2>" - #echo - #echo "SIP-ID: $TMP_UUID" - #echo - #exit $? - ;; - add) - if [ $# -ne 3 ] ; then - usage_alias_db - exit 1 - fi - shift - check_aor "$1" - if [ "$?" -ne "0" ] ; then - err "alias_db - $1 is not a valid AoR (user@domain)" - exit 1 - fi - - check_aor "$2" - if [ "$?" -ne "0" ] ; then - err "alias_db - $2 is not a valid AoR (user@domain)" - exit 1 - fi - - set_user $1 - TMP_OSERUSER=$OSERUSER - TMP_OSERDOMAIN=$OSERDOMAIN - set_user $2 - - if is_value_in_db $DA_TABLE $DA_ALIAS_USER_COLUMN $TMP_OSERUSER; then - minfo "$TMP_OSERUSER alias already in $DA_TABLE table" - exit 0 - fi - - QUERY="INSERT INTO $DA_TABLE ($DA_USER_COLUMN,$DA_DOMAIN_COLUMN,\ -$DA_ALIAS_USER_COLUMN,$DA_ALIAS_DOMAIN_COLUMN) VALUES ('$OSERUSER',\ -'$OSERDOMAIN','$TMP_OSERUSER','$TMP_OSERDOMAIN' );" - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "alias_db - SQL Error" - exit 1 - fi - - exit $? - ;; - rm) - if [ $# -ne 2 ] ; then - merr "alias_db - wrong numbers of parameters" - usage_alias_db - exit 1 - fi - - shift - - check_aor "$1" - if [ "$?" -ne "0" ] ; then - merr "alias_db - $1 is not a valid URI" - exit 1 - fi - - set_user $1 - CLAUSE="WHERE $DA_ALIAS_USER_COLUMN='$OSERUSER' AND \ -$DA_ALIAS_DOMAIN_COLUMN='$OSERDOMAIN'" - QUERY="DELETE FROM $DA_TABLE $CLAUSE;" - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "alias_db - SQL Error" - exit 1 - fi - - exit $? - ;; - - help) - usage_alias_db "alone" - ;; - - *) - usage_alias_db - exit 1 - ;; - esac -} # end db-aliases - - -# -##### ------------------------------------------------ ##### -### AVP management -# -# avp list [-T table] [-u ] -# [-a attribute] [-v value] [-t type] ... list AVPs -# avp add [-T table] -# ............ add AVP (*) -# avp rm [-T table] [-u ] -# [-a attribute] [-v value] [-t type] ... remove AVP (*) - -avpops() { - require_dbengine - if [ "$#" -lt 2 ] ; then - merr "avp - too few parameters" - minfo "see '$0 avp help'" - exit 1 - fi - if [ "$1" = "avp" ] ; then - shift - else - merr "avp - unknown command $1" - minfo "see '$0 avp help'" - exit 1 - fi - - case $1 in - list) - shift - CLAUSE="" - while [ "$#" != "0" ] - do - TMP_ARG=$1 - shift - case $TMP_ARG in - -T) - if [ -z "$1" ] ; then - merr "avp list - table name parameter missing" - exit 1 - fi - AVP_TABLE=$1 - ;; - -u) - if [ -z "$1" ] ; then - merr "avp list - user id or uuid parameter missing" - exit 1 - fi - is_aor "$1" - if [ "$?" -eq "0" ] ; then - set_user $1 - if [ "$CLAUSE" = "" ] ; then - CLAUSE=" WHERE $AVP_USER_COLUMN='$OSERUSER' \ -AND $AVP_DOMAIN_COLUMN='$OSERDOMAIN'" - else - CLAUSE="$CLAUSE AND \ -$AVP_USER_COLUMN='$OSERUSER' AND $AVP_DOMAIN_COLUMN='$OSERDOMAIN'" - fi - else - if [ "$CLAUSE" = "" ] ; then - CLAUSE=" WHERE $AVP_UUID_COLUMN='$1'" - else - CLAUSE="$CLAUSE AND $AVP_UUID_COLUMN='$1'" - fi - fi - ;; - -a) - if [ -z "$1" ] ; then - merr "avp list - attribute name parameter missing" - exit 1 - fi - if [ "$CLAUSE" = "" ] ; then - CLAUSE=" WHERE $AVP_ATTRIBUTE_COLUMN='$1'" - else - CLAUSE="$CLAUSE AND $AVP_ATTRIBUTE_COLUMN='$1'" - fi - ;; - -v) - if [ -z "$1" ] ; then - merr "avp list - value parameter missing" - exit 1 - fi - if [ "$CLAUSE" = "" ] ; then - CLAUSE=" WHERE $AVP_VALUE_COLUMN='$1'" - else - CLAUSE="$CLAUSE AND $AVP_VALUE_COLUMN='$1'" - fi - ;; - -t) - if [ -z "$1" ] ; then - merr "avp list - type parameter missing" - exit 1 - fi - if [ "$CLAUSE" = "" ] ; then - CLAUSE=" WHERE $AVP_TYPE_COLUMN='$1'" - else - CLAUSE="$CLAUSE AND $AVP_TYPE_COLUMN='$1'" - fi - ;; - *) - merr "avp list - unknown parameter $1" - exit 1 - ;; - esac - shift - done - - QUERY="SELECT $AVP_UUID_COLUMN,$AVP_USER_COLUMN,\ -$AVP_DOMAIN_COLUMN,$AVP_ATTRIBUTE_COLUMN,$AVP_TYPE_COLUMN,$AVP_VALUE_COLUMN \ -FROM $AVP_TABLE $CLAUSE;" - mdbg "Query: $QUERY" - mecho "Dumping AVPs" - echo - $DBROCMD "$QUERY" - # | $AWK 'BEGIN {line=0;} - # /^\+/ { next } - # { if(line==0) print "## UUID \tUserID \tAttribute \tType \tValue\n"; - # else { - # ORS_BAK=ORS; - # ORS=""; - # print line ") " $1 $2 "@" $3 "\t" $4 "\t\"" $5; - # for (i=6;i<=NF;++i) print FS $i; - # ORS=ORS_BAK; - # print "\""; - # } - # line++; - # }' - - exit $? - ;; - - add) - shift - if [ $# -ne 4 ] ; then - if [ $# -ne 6 ] ; then - merr "avp add - bad number of parameters" - exit 1 - fi - fi - if [ $# -eq 6 ] ; then - if [ "$1" = "-T" ] ; then - AVP_TABLE=$2 - shift - shift - else - mecho "avp add - unknown parameter '$1'" - exit 1 - fi - fi - - is_aor "$1" - if [ "$?" -eq "0" ] ; then - set_user $1 - else - AVP_UUID=$1 - fi - - QUERY="INSERT INTO $AVP_TABLE \ -($AVP_UUID_COLUMN,$AVP_USER_COLUMN,$AVP_DOMAIN_COLUMN,$AVP_ATTRIBUTE_COLUMN,\ -$AVP_TYPE_COLUMN,$AVP_VALUE_COLUMN,$AVP_MODIFIED_COLUMN) \ -VALUES ('$AVP_UUID','$OSERUSER','$OSERDOMAIN','$2',$3,'$4',$DBFNOW);" - # echo "Query: $QUERY" - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "avp add - SQL Error" - exit 1 - else - echo - mecho "avp add - attribute added" - fi - - exit $? - ;; - - rm) - shift - CLAUSE="" - while [ "$#" != "0" ] - do - TMP_ARG=$1 - shift - case $TMP_ARG in - -T) - if [ -z "$1" ] ; then - merr "avp rm - table name parameter missing" - exit 1 - fi - AVP_TABLE=$1 - ;; - -u) - if [ -z "$1" ] ; then - merr "avp rm - user id or uuid parameter missing" - exit 1 - fi - is_aor "$1" - if [ "$?" -eq "0" ] ; then - set_user $1 - if [ "$CLAUSE" = "" ] ; then - CLAUSE="WHERE $AVP_USER_COLUMN='$OSERUSER' \ -AND $AVP_DOMAIN_COLUMN='$OSERDOMAIN'" - else - CLAUSE="$CLAUSE AND \ -$AVP_USER_COLUMN='$OSERUSER' AND $AVP_DOMAIN_COLUMN='$OSERDOMAIN'" - fi - else - if [ "$CLAUSE" = "" ] ; then - CLAUSE="WHERE $AVP_UUID_COLUMN='$1'" - else - CLAUSE="$CLAUSE AND $AVP_UUID_COLUMN='$1'" - fi - fi - ;; - -a) - if [ -z "$1" ] ; then - merr "avp rm - attribute name parameter missing" - exit 1 - fi - if [ "$CLAUSE" = "" ] ; then - CLAUSE="WHERE $AVP_ATTRIBUTE_COLUMN='$1'" - else - CLAUSE="$CLAUSE AND $AVP_ATTRIBUTE_COLUMN='$1'" - fi - ;; - -v) - if [ -z "$1" ] ; then - merr "avp rm - value parameter missing" - exit 1 - fi - if [ "$CLAUSE" = "" ] ; then - CLAUSE="WHERE $AVP_VALUE_COLUMN='$1'" - else - CLAUSE="$CLAUSE AND $AVP_VALUE_COLUMN='$1'" - fi - ;; - -t) - if [ -z "$1" ] ; then - merr "avp rm - type parameter missing" - exit 1 - fi - if [ "$CLAUSE" = "" ] ; then - CLAUSE="WHERE $AVP_TYPE_COLUMN='$1'" - else - CLAUSE="$CLAUSE AND $AVP_TYPE_COLUMN='$1'" - fi - ;; - *) - merr "avp rm - unknown parameter $1" - exit 1 - ;; - esac - shift - done - QUERY="DELETE FROM $AVP_TABLE $CLAUSE;" - mdbg "Query: $QUERY" - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "avp rm - SQL Error" - exit 1 - else - echo - mecho "avp rm - AVP(s) deleted" - fi - - exit $? - ;; - - help) - usage_avp - ;; - - *) - merr "avp - unknown command" - usage - exit 1 - ;; - esac -} # end avpops() - -# -##### ------------------------------------------------ ##### -### cisco restart -# -cisco_restart() { - require_ctlengine - myhost=`get_my_host` - CMDPARAMS="= tm.t_uac_start NOTIFY \"$1\" \".\" \".\" \"From:sip:daemon@$myhost=CRLF=To:<$1>=CRLF=Event:check-sync=CRLF=Contact:sip:daemon@$myhost=CRLF=\"" - - if [ $CTLENGINETYPE -eq 1 ] ; then - ctl_cmd_run $CMDPARAMS - else - RET=`ctl_cmd_run $CMDPARAMS | head -1` - print_status $RET - fi -} - -# -##### ------------------------------------------------ ##### -### DB operations -# -db_ops() { - require_dbengine - case $1 in - exec|query) - shift - if [ $# -ne 1 ] ; then - merr "missing query parameter" - exit 1 - fi - $DBCMD "$1" - ;; - roexec|roquery) - shift - if [ $# -ne 1 ] ; then - merr "missing query parameter" - exit 1 - fi - $DBROCMD "$1" - ;; - run) - shift - if [ $# -ne 1 ] ; then - merr "missing query parameter" - exit 1 - fi - eval QUERY=\$$1 - if [ -z "$QUERY" ] ; then - merr "missing query value" - exit 1 - fi - $DBCMD "$QUERY" - ;; - rorun) - shift - if [ $# -ne 1 ] ; then - merr "missing query parameter" - exit 1 - fi - eval QUERY=\$$1 - if [ -z "$QUERY" ] ; then - merr "missing query value" - exit 1 - fi - $DBROCMD "$QUERY" - ;; - show) - shift - if [ $# -ne 1 ] ; then - merr "missing table parameter" - exit 1 - fi - QUERY="select * FROM $1;" - $DBROCMD "$QUERY" - ;; - showg) - shift - if [ $# -ne 1 ] ; then - merr "missing table parameter" - exit 1 - fi - QUERY="select * FROM $1\\G;" - $DBROCMD "$QUERY" - ;; - smatch) - shift - if [ $# -ne 3 ] ; then - merr "missing parameters" - exit 1 - fi - QUERY="SELECT * FROM $1 WHERE $2='$3'\\G;" - $DBROCMD "$QUERY" - ;; - nmatch) - shift - if [ $# -ne 3 ] ; then - merr "missing parameters" - exit 1 - fi - QUERY="SELECT * FROM $1 WHERE $2=$3\\G;" - $DBROCMD "$QUERY" - ;; - connect) - shift - if [ -z "$DBCMDCONNECT" ] ; then - merr "extension not implemented" - exit 1 - fi - $DBCMDCONNECT - ;; - version) - shift - if [ $# -ne 3 ] ; then - merr "missing parameters" - exit 1 - fi - case $1 in - add) - QUERY="INSERT INTO version (table_name, table_version) VALUES ('$2', $3);" - $DBCMD "$QUERY" - ;; - set) - QUERY="DELETE FROM version WHERE table_name='$2';" - $DBCMD "$QUERY" - QUERY="INSERT INTO version (table_name, table_version) VALUES ('$2', $3);" - $DBCMD "$QUERY" - ;; - update) - QUERY="UPDATE version SET table_version=$3 WHERE table_name='$2';" - $DBCMD "$QUERY" - ;; - *) - usage_db_ops - exit 1 - esac - ;; - *) - usage_db_ops - exit 1 - esac -} - -# -##### ------------------------------------------------ ##### -### domain management -# -domain() { - case $1 in - reload) - require_ctlengine - ctl_cmd_run domain.reload - ;; - show) - require_ctlengine - ctl_cmd_run domain.dump - ;; - showdb) - require_dbengine - QUERY="select * FROM $DOMAIN_TABLE ; " - $DBROCMD "$QUERY" - ;; - add) - require_dbengine - shift - if [ $# -ne 1 ] ; then - merr "missing domain parameter" - exit 1 - fi - if is_value_in_db $DOMAIN_TABLE $DO_DOMAIN_COLUMN $1; then - minfo "$1 already in $DOMAIN_TABLE table" - exit 0 - fi - QUERY="insert into $DOMAIN_TABLE ($DO_DOMAIN_COLUMN, \ - $DO_LAST_MODIFIED_COLUMN) VALUES ('$1',$DBFNOW);" - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "domain - SQL Error" - exit 1 - fi - minfo "execute '$0 domain reload' to synchronize cache and database" - ;; - rm) - require_dbengine - shift - if [ $# -ne 1 ] ; then - merr "missing domain parameter" - exit 1 - fi - QUERY="delete from $DOMAIN_TABLE where domain='$1';" - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "domain - SQL Error" - exit 1 - fi - minfo "execute '$0 domain reload' to synchronize cache and database" - ;; - *) - usage_domain - exit 1 - esac -} - -# -##### ------------------------------------------------ ##### -### uid_domain management -# -uid_domain() { - case $1 in - reload) - require_kamcmd - $SERCTLCMD domain.reload - ;; - show) - require_kamcmd - $SERCTLCMD domain.dump - ;; - showdb) - require_dbengine - QUERY="select * FROM $UID_DOMAIN_TABLE ; " - $DBROCMD "$QUERY" - ;; - add) - require_dbengine - shift - if [ $# -lt 1 ] ; then - merr "too few parameters" - exit 1 - fi - - DOMAIN=$1 - DID=$2 - FLAGS=$3 - - if [ -z "$2" ] ; then - DID=$DOMAIN - fi - if [ -z "$3" ] ; then - FLAGS=$(( $SRDB_LOAD_SER | $SRDB_CANON | $SRDB_FOR_SERWEB )) - fi - - if is_value_in_db $UID_DOMAIN_TABLE $UID_DO_DOMAIN_COLUMN $DOMAIN; then - minfo "$1 already in $UID_DOMAIN_TABLE table" - exit 0 - fi - QUERY="insert into $UID_DOMAIN_TABLE ($UID_DO_DID_COLUMN,$UID_DO_DOMAIN_COLUMN,$UID_DO_FLAGS_COLUMN) VALUES ('$DID','$DOMAIN',$FLAGS);" - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "uid_domain - SQL Error" - exit 1 - fi - minfo "execute '$0 uid_domain reload' to synchronize cache and database" - ;; - rm) - require_dbengine - shift - if [ $# -ne 1 ] ; then - merr "missing domain parameter" - exit 1 - fi - QUERY="delete from $UID_DOMAIN_TABLE where domain='$1';" - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "domain - SQL Error" - exit 1 - fi - minfo "execute '$0 uid_domain reload' to synchronize cache and database" - ;; - *) - usage_uid_domain - exit 1 - esac -} - -# -##### ------------------------------------------------ ##### -### permissions trusted management -# -permissions_trusted() { - case $1 in - reload) - require_ctlengine - ctl_cmd_run permissions.trustedReload - ;; - dump) - require_ctlengine - ctl_cmd_run permissions.trustedDump - ;; - show) - require_dbengine - QUERY="select * FROM $TRUSTED_TABLE ; " - $DBROCMD "$QUERY" - ;; - add) - require_dbengine - shift - if [ $# -lt 2 ] ; then - usage_trusted - exit 1 - fi - if is_value_in_db $TRUSTED_TABLE src_ip $1; then - minfo "$1 already in $TRUSTED_TABLE table" - exit 0 - fi - case $2 in - any|udp|tcp|tls|sctp|none) - ;; - *) - merr "unknown protocol" - exit 1 - esac - PATTERN="" - if [ ! -z "$3" ]; then - PATTERN="$3" - fi - - QUERY="insert into $TRUSTED_TABLE \ - ( $TRUSTED_SRC_IP_COLUMN, $TRUSTED_PROTO_COLUMN, \ - $TRUSTED_FROM_PATTERN_COLUMN, $TRUSTED_TAG_COLUMN) \ - VALUES ('$1', '$2', '$PATTERN', '$4');" - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "trusted - SQL Error" - exit 1 - fi - minfo "execute '$0 trusted reload' to synchronize cache and database" - ;; - rm) - require_dbengine - shift - if [ $# -ne 1 ] ; then - usage_trusted - exit 1 - fi - QUERY="delete from $TRUSTED_TABLE where $TRUSTED_SRC_IP_COLUMN='$1';" - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "trusted - SQL Error" - exit 1 - fi - minfo "execute '$0 trusted reload' to synchronize cache and database" - ;; - *) - usage_trusted - exit 1 - esac -} - - -# -##### ------------------------------------------------ ##### -### permissions address management -# -permissions_address() { - case $1 in - reload) - require_ctlengine - ctl_cmd_run permissions.addressReload - ;; - dump) - require_ctlengine - ctl_cmd_run permissions.addressDump - ctl_cmd_run permissions.subnetDump - ;; - show) - require_dbengine - QUERY="select * FROM $ADDRESS_TABLE ; " - $DBROCMD "$QUERY" - ;; - add) - require_dbengine - shift - if [ $# -lt 2 ] ; then - usage_address - exit 1 - fi - AMASK=32 - if [ ! -z "$3" ]; then - AMASK="$3" - fi - APORT=0 - if [ ! -z "$4" ]; then - APORT="$4" - fi - ATAG="" - if [ ! -z "$5" ]; then - ATAG="$5" - fi - - QUERY="insert into $ADDRESS_TABLE \ - (grp, ip_addr, mask, port, tag) \ - VALUES ($1, '$2', $AMASK, $APORT, '$ATAG');" - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "permissions address - SQL Error" - exit 1 - fi - minfo "execute '$0 address reload' to synchronize cache and database" - ;; - rm) - require_dbengine - shift - if [ $# -ne 2 ] ; then - usage_address - exit 1 - fi - QUERY="delete from $ADDRESS_TABLE where grp=$1 and ip_addr='$2';" - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "permissions address - SQL Error" - exit 1 - fi - minfo "execute '$0 address reload' to synchronize cache and database" - ;; - *) - usage_address - exit 1 - esac -} - - -# -##### ------------------------------------------------ ##### -### mtree management -# -mtree_management() { - case $1 in - reload) - require_ctlengine - ctl_cmd_run mtree.reload $2 - ;; - dump) - require_ctlengine - ctl_cmd_run mtree.list $2 - ;; - showdb) - require_dbengine - QUERY="select * FROM $2 ; " - $DBROCMD "$QUERY" - ;; - add) - require_dbengine - if [ $# -lt 4 ] ; then - usage_mtree - exit 1 - fi - - QUERY="INSERT INTO $2 \ - (tprefix, tvalue) \ - VALUES ($3, '$4');" - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "mtree - SQL Error" - exit 1 - fi - minfo "execute '$0 mtree reload' to synchronize cache and database" - ;; - rm) - require_dbengine - shift - if [ $# -ne 3 ] ; then - usage_address - exit 1 - fi - QUERY="DELETE FROM $2 where tprefix='$3';" - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "mtree - SQL Error" - exit 1 - fi - minfo "execute '$0 mtree reload' to synchronize cache and database" - ;; - *) - usage_mtree - exit 1 - esac -} - - -# -##### ------------------------------------------------ ##### -### LCR management -# -lcr() { - case $1 in - show_gws) - merr "command disabled" - exit 1 - require_dbengine - mecho "lcr gateways" - QUERY="select * FROM $GW_TABLE ORDER BY $LCR_ID_COLUMN, $LCR_GW_GRPID_COLUMN; " - $DBROCMD "$QUERY" - ;; - show_routes) - merr "command disabled" - exit 1 - require_dbengine - mecho "lcr routes" - QUERY="select * FROM $LCR_TABLE ORDER BY $LCR_ID_COLUMN, $LCR_PREFIX_COLUMN; " - $DBROCMD "$QUERY" - ;; - reload) - merr "command disabled" - exit 1 - ctl_cmd_run lcr.reload - ;; - dump_gws) - merr "command disabled" - exit 1 - ctl_cmd_run lcr.dump_gws - ;; - dump_routes) - merr "command disabled" - exit 1 - ctl_cmd_run lcr.dump_lcrs - ;; - eval_weights) - shift - $AWK 'BEGIN { - if (ARGC < 2) { - printf("Usage: lcr eval_weights \n"); - exit; - } - iters = 100000; - for (i = 1; i < ARGC; i++) { counts[i] = 0; } - for (i = 1; i <= iters; i++) { - for (j = 1; j < ARGC; j++) { - elem[j] = ARGV[j] * rshift(int(2147483647 * rand()), 8); - } - at = 1; - max = elem[at]; - for (j = 2; j < ARGC; j++) { - if (elem[j] > max) { - max = elem[j]; - at = j; - } - } - counts[at] = counts[at] + 1; - } - for (i = 1; i < ARGC; i++) { - printf("weight %d probability %.4f\n", ARGV[i], counts[i]/iters); - } - }' $@ - ;; - *) - usage_lcr - exit 1 - esac -} - -# -##### ------------------------------------------------ ##### -### CARRIERROUTE management -# -cr() { - require_dbengine - require_ctlengine - case $1 in - show) - mecho "cr carrier names" - QUERY="select * FROM $CARRIER_NAME_TABLE ORDER BY $CARRIERROUTE_CARRIER_NAME_ID_COLUMN; " - $DBROCMD "$QUERY" - mecho "cr domain names" - QUERY="select * FROM $DOMAIN_NAME_TABLE ORDER BY $CARRIERROUTE_DOMAIN_NAME_ID_COLUMN; " - $DBROCMD "$QUERY" - mecho "cr routes" - QUERY="select * FROM $CARRIERROUTE_TABLE ORDER BY \ - $CARRIERROUTE_CARRIERROUTE_CARRIER_COLUMN,\ - $CARRIERROUTE_CARRIERROUTE_SCAN_PREFIX_COLUMN,\ - $CARRIERROUTE_CARRIERROUTE_DOMAIN_COLUMN,\ - $CARRIERROUTE_CARRIERROUTE_PROB_COLUMN;" - $DBROCMD "$QUERY" - ;; - reload) - ctl_cmd_run cr.reload_routes - ;; - - dump) - ctl_cmd_run cr.dump_routes - ;; - - addcn) - shift - if [ $# -ne 2 ] ; then - merr "cr - missing carrier id or name" - exit 1 - fi - QUERY="insert into $CARRIER_NAME_TABLE - ( $CARRIERROUTE_CARRIER_NAME_ID_COLUMN, \ - $CARRIERROUTE_CARRIER_NAME_CARRIER_COLUMN) \ - VALUES ($1, '$2');" - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "cr - SQL Error" - exit 1 - fi - minfo "execute '$0 cr reload' to synchronize cache and database" - ;; - - rmcn) - shift - if [ $# -ne 1 ] ; then - merr "cr - missing carrier id to be removed" - exit 1 - fi - QUERY="delete from $CARRIER_NAME_TABLE where $CARRIERROUTE_CARRIER_NAME_ID_COLUMN='$1';" - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "cr - SQL Error" - exit 1 - fi - minfo "execute '$0 cr reload' to synchronize cache and database" - ;; - - adddn) - shift - if [ $# -ne 2 ] ; then - merr "cr - missing domain id or name" - exit 1 - fi - QUERY="insert into $DOMAIN_NAME_TABLE - ( $CARRIERROUTE_DOMAIN_NAME_ID_COLUMN, \ - $CARRIERROUTE_DOMAIN_NAME_DOMAIN_COLUMN) \ - VALUES ($1, '$2');" - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "cr - SQL Error" - exit 1 - fi - minfo "execute '$0 cr reload' to synchronize cache and database" - ;; - - rmdn) - shift - if [ $# -ne 1 ] ; then - merr "cr - missing domain id to be removed" - exit 1 - fi - QUERY="delete from $DOMAIN_NAME_TABLE where $CARRIERROUTE_DOMAIN_NAME_ID_COLUMN='$1';" - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "cr - SQL Error" - exit 1 - fi - minfo "execute '$0 cr reload' to synchronize cache and database" - ;; - - addcarrier) - shift - if [ $# -lt 4 ] ; then - merr "cr - too few parameters" - exit 1 - fi - PROB=1 - STRIP=0 - REWRITE_PREFIX= - REWRITE_SUFFIX= - COMMENT= - FLAGS=0 - MASK=0 - if [ $# -gt 4 ] ; then - PROB=$5 - if [ $# -gt 5 ] ; then - STRIP=$6 - if [ $# -gt 6 ] ; then - REWRITE_PREFIX=$7 - if [ $# -gt 7 ] ; then - REWRITE_SUFFIX=$8 - if [ $# -gt 8 ] ; then - MASK=$9 - if [ $# -gt 9 ] ; then - FLAGS=${10} - if [ $# -gt 10 ] ; then - COMMENT=${11} - fi - fi - fi - fi - fi - fi - fi - CARRIER=$1 - SCAN_PREFIX=$2 - DOMAIN=$3 - REWRITE_HOST=$4 - echo $FLAGS - echo $MASK - QUERY="insert into $CARRIERROUTE_TABLE \ - ( $CARRIERROUTE_CARRIERROUTE_CARRIER_COLUMN, \ - $CARRIERROUTE_CARRIERROUTE_SCAN_PREFIX_COLUMN, \ - $CARRIERROUTE_CARRIERROUTE_DOMAIN_COLUMN, \ - $CARRIERROUTE_CARRIERROUTE_PROB_COLUMN, \ - $CARRIERROUTE_CARRIERROUTE_STRIP_COLUMN, \ - $CARRIERROUTE_CARRIERROUTE_REWRITE_HOST_COLUMN, \ - $CARRIERROUTE_CARRIERROUTE_REWRITE_PREFIX_COLUMN, \ - $CARRIERROUTE_CARRIERROUTE_REWRITE_SUFFIX_COLUMN, \ - $CARRIERROUTE_CARRIERROUTE_COMMENT_COLUMN, \ - $CARRIERROUTE_CARRIERROUTE_FLAGS_COLUMN, \ - $CARRIERROUTE_CARRIERROUTE_MASK_COLUMN ) \ - VALUES ($CARRIER, '$SCAN_PREFIX', '$DOMAIN', $PROB, $STRIP, \ - '$REWRITE_HOST', '$REWRITE_PREFIX', '$REWRITE_SUFFIX', '$COMMENT', \ - $FLAGS, $MASK);" - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "cr - SQL Error" - exit 1 - fi - minfo "execute '$0 cr reload' to synchronize cache and database" - ;; - - rmcarrier) - shift - if [ $# -ne 3 ] ; then - merr "cr - too few parameters" - exit 1 - fi - CARRIER=$1 - SCAN_PREFIX=$2 - DOMAIN=$3 - QUERY="delete from $CARRIERROUTE_TABLE where $CARRIERROUTE_CARRIERROUTE_CARRIER_COLUMN='$CARRIER' AND \ - $CARRIERROUTE_CARRIERROUTE_SCAN_PREFIX_COLUMN='$SCAN_PREFIX' AND \ - $CARRIERROUTE_CARRIERROUTE_DOMAIN_COLUMN=$DOMAIN ;" - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "cr - SQL Error" - exit 1 - fi - minfo "execute '$0 cr reload' to synchronize cache and database" - ;; - - *) - usage_cr - exit 1 - esac -} - -# -##### ------------------------------------------------ ##### -### DISPATCHER management -# -dispatcher() { - case $1 in - show) - require_dbengine - mecho "dispatcher gateways" - QUERY="select * FROM $DISPATCHER_TABLE ORDER BY $DISPATCHER_SETID_COLUMN; " - $DBROCMD "$QUERY" - ;; - addgw|add) - require_dbengine - shift - if [ $# -lt 2 ] ; then - merr "too few parameters" - usage_dispatcher - exit 1 - fi - - DISPATCHER_SETID=$1 - DISPATCHER_DESTINATION=$2 - - if [ $# -gt 2 ] ; then - DISPATCHER_FLAGS=$3 - else - DISPATCHER_FLAGS=0 - fi - - if [ $# -gt 3 ] ; then - DISPATCHER_PRIORITY=$4 - else - DISPATCHER_PRIORITY=0 - fi - - if [ $# -gt 4 ] ; then - DISPATCHER_ATTRS=$5 - else - DISPATCHER_ATTRS="" - fi - - if [ $# -gt 5 ] ; then - DISPATCHER_DESCRIPTION=$6 - else - DISPATCHER_DESCRIPTION="" - fi - - QUERY="insert into $DISPATCHER_TABLE \ - ( $DISPATCHER_SETID_COLUMN, $DISPATCHER_DESTINATION_COLUMN, $DISPATCHER_FLAGS_COLUMN, $DISPATCHER_PRIORITY_COLUMN, $DISPATCHER_ATTRS_COLUMN, $DISPATCHER_DESCRIPTION_COLUMN ) \ - VALUES ($DISPATCHER_SETID,'$DISPATCHER_DESTINATION',$DISPATCHER_FLAGS,$DISPATCHER_PRIORITY,'$DISPATCHER_ATTRS','$DISPATCHER_DESCRIPTION');" - $DBCMD "$QUERY" - - if [ $? -ne 0 ] ; then - merr "dispatcher - SQL Error" - exit 1 - fi - - ;; - rmgw|rm) - require_dbengine - shift - if [ $# -ne 1 ] ; then - merr "missing gateway id to be removed" - exit 1 - fi - - QUERY="delete from $DISPATCHER_TABLE where $DISPATCHER_ID_COLUMN='$1';" - $DBCMD "$QUERY" - - if [ $? -ne 0 ] ; then - merr "dispatcher - SQL Error" - exit 1 - fi - - ;; - reload) - require_ctlengine - ctl_cmd_run dispatcher.reload - ;; - - dump) - require_ctlengine - ctl_cmd_run dispatcher.list - ;; - - *) - usage_dispatcher - exit 1 - - esac -} - -# -##### ------------------------------------------------ ##### -### Server management -# -ksr_srv() { - case $1 in - sockets) - require_ctlengine - mecho "list listen sockets" - ctl_cmd_run corex.list_sockets - ;; - aliases) - require_ctlengine - mecho "list server aliases" - ctl_cmd_run corex.list_aliases - ;; - rpclist) - require_ctlengine - mecho "list server rpc commands" - ctl_cmd_run system.listMethods - ;; - version) - require_ctlengine - mecho "list server version" - ctl_cmd_run core.version - ;; - *) - usage_ksr_srv - exit 1 - - esac -} - - -# -##### ------------------------------------------------ ##### -### DIALOG management -# -dialog() { - case $1 in - show|list) - require_ctlengine - mecho "dialog memory records" - ctl_cmd_run dlg.list - ;; - showdb) - require_dbengine - mecho "dialog database records" - QUERY="select * FROM $DIALOG_TABLE ORDER BY id; " - $DBROCMD "$QUERY" - ;; - *) - usage_dialog - exit 1 - - esac -} - -# -##### ------------------------------------------------ ##### -### DIALPLAN management -# -dialplan() { - require_dbengine - require_ctlengine - case $1 in - show) - shift - if [ $# -gt 0 ] ; then - mecho "dialplan $1 tables" - QUERY="select * FROM $DIALPLAN_TABLE WHERE $DIALPLAN_DPID_COLUMN=$1 ORDER BY $DIALPLAN_PR_COLUMN ; " - else - mecho "dialplan tables" - QUERY="select * FROM $DIALPLAN_TABLE ORDER BY $DIALPLAN_DPID_COLUMN, $DIALPLAN_PR_COLUMN; " - fi - $DBROCMD "$QUERY" - ;; - - addrule) - shift - if [ $# -lt 4 ] ; then - merr "too few parameters" - usage_dialplan - exit 1 - fi - - DIALPLAN_DPID=$1 - DIALPLAN_PR=$2 - DIALPLAN_MATCH_OP=$3 - case $DIALPLAN_MATCH_OP in - equal) - DIALPLAN_MATCH_OP=0 - ;; - regexp) - DIALPLAN_MATCH_OP=1 - ;; - fnmatch) - DIALPLAN_MATCH_OP=2 - ;; - *) - merr "dialplan - unexpected $DIALPLAN_MATCH_OP for operating matching. Use 'equal' or 'regexp'!" - exit 1 - esac - DIALPLAN_MATCH_EXP=$4 - DIALPLAN_MATCH_LEN=0 - if [ $# -gt 4 ] ; then - DIALPLAN_MATCH_LEN=$5 - fi - if [ $# -gt 5 ] ; then - DIALPLAN_SUBST_EXP=$6 - fi - if [ $# -gt 6 ] ; then - DIALPLAN_REPL_EXP=$7 - fi - if [ $# -gt 7 ] ; then - DIALPLAN_ATTRS=$8 - fi - - QUERY="insert into $DIALPLAN_TABLE \ - ( $DIALPLAN_DPID_COLUMN, $DIALPLAN_PR_COLUMN, $DIALPLAN_MATCH_OP_COLUMN, \ - $DIALPLAN_MATCH_EXP_COLUMN, $DIALPLAN_MATCH_LEN_COLUMN, \ - $DIALPLAN_SUBST_EXP_COLUMN, $DIALPLAN_REPL_EXP_COLUMN, \ - $DIALPLAN_ATTRS_COLUMN ) \ - VALUES ( $DIALPLAN_DPID, $DIALPLAN_PR, $DIALPLAN_MATCH_OP, \ - '$DIALPLAN_MATCH_EXP', $DIALPLAN_MATCH_LEN, '$DIALPLAN_SUBST_EXP', \ - '$DIALPLAN_REPL_EXP', '$DIALPLAN_ATTRS')"; - mdbg "$QUERY" - $DBCMD "$QUERY" - - if [ $? -ne 0 ] ; then - merr "dialplan - SQL Error" - exit 1 - fi - - minfo "do not forget to do dialplan reload" - ;; - - rm) - QUERY="delete from $DIALPLAN_TABLE; " - $DBCMD "$QUERY" - - if [ $? -ne 0 ] ; then - merr "dialplan - SQL Error" - exit 1 - fi - - minfo "do not forget to do dialplan reload" - ;; - - rmdpid) - shift - if [ $# -lt 1 ] ; then - merr "too few parameters" - usage_dialplan - exit 1 - fi - - DIALPLAN_DPID=$1 - - QUERY="delete from $DIALPLAN_TABLE where $DIALPLAN_DPID_COLUMN=$DIALPLAN_DPID; " - $DBCMD "$QUERY" - - if [ $? -ne 0 ] ; then - merr "dialplan - SQL Error" - exit 1 - fi - - minfo "do not forget to do dialplan reload" - ;; - - rmrule) - shift - if [ $# -lt 2 ] ; then - merr "too few parameters" - usage_dialplan - exit 1 - fi - - DIALPLAN_DPID=$1 - DIALPLAN_PR=$2 - - QUERY="delete from $DIALPLAN_TABLE where $DIALPLAN_DPID_COLUMN=$DIALPLAN_DPID AND $DIALPLAN_PR_COLUMN=$DIALPLAN_PR; " - $DBCMD "$QUERY" - - if [ $? -ne 0 ] ; then - merr "dialplan - SQL Error" - exit 1 - fi - - minfo "do not forget to do dialplan reload" - ;; - - reload) - ctl_cmd_run dialplan.reload - ;; - - *) - usage_dialplan - exit 1 - - esac -} - -# -##### ------------------------------------------------ ##### -### kamailio_start -# -kamailio_start() { - echo - minfo "Starting Kamailio : " - if [ -r $PID_FILE ] ; then - ps axw | $EGREP kamailio - ls -l $PID_FILE - minfo "PID file exists ($PID_FILE)! Kamailio already running?" - exit 1 - fi - - if [ ! -x "$KAMBIN" ] ; then - echo - merr "Kamailio binaries not found at $KAMBIN" - merr "set KAMBIN to the path of kamailio in $0 or ~/.kamctlrc" - exit 1 - fi - if [ $SYSLOG = 1 ] ; then - $KAMBIN -P $PID_FILE -f $ETCDIR/kamailio.cfg $STARTOPTIONS 1>/dev/null 2>/dev/null - else - $KAMBIN -P $PID_FILE -E -f $ETCDIR/kamailio.cfg $STARTOPTIONS - fi - sleep 3 - if [ ! -s $PID_FILE ] ; then - echo - merr "PID file $PID_FILE does not exist -- Kamailio start failed" - exit 1 - fi - minfo "started (pid: `cat $PID_FILE`)" -} - -# -##### ------------------------------------------------ ##### -### kamailio_stop -# -kamailio_stop() { - echo - minfo "Stopping Kamailio : " - if [ -r $PID_FILE ] ; then - kill `cat $PID_FILE` - minfo "stopped" - else - echo - merr "No PID file found ($PID_FILE)! Kamailio probably not running" - minfo "check with 'ps axw | $EGREP kamailio'" - exit 1 - fi -} - -# -##### ------------------------------------------------ ##### -### options_ping -# -options_ping() { - myhost=`get_my_host` - require_ctlengine - CMDPARAMS="= tm.t_uac_wait_block OPTIONS \"$1\" \".\" \".\" \"From:sip:daemon@$myhost=CRLF=To:<$1>=CRLF=Contact:sip:daemon@$myhost=CRLF=\"" - if [ $CTLENGINETYPE -eq 1 ] ; then - ctl_cmd_run $CMDPARAMS - else - RET=`ctl_cmd_run $CMDPARAMS | head -1` - print_status $RET - fi -} - -# -##### ------------------------------------------------ ##### -### rpid management -# -rpid() { - if [ "$#" -lt 2 ] ; then - merr "rpid - too few parameters" - exit 1 - fi - shift; - require_dbengine - case $1 in - show) - if [ $# -eq 2 ] ; then - set_user $2 - is_user $2 - if [ $? -ne 0 ] ; then - merr "rpid - invalid user '$2'" - exit 1; - fi - CLAUSE=" WHERE $SUBSCRIBER_COLUMN='$OSERUSER' AND \ -$REALM_COLUMN='$OSERDOMAIN' " - elif [ $# -ne 1 ] ; then - usage_rpid - exit 1 - fi - QUERY="select $SUBSCRIBER_COLUMN, $RPID_COLUMN FROM $SUB_TABLE \ -$CLAUSE ; " - $DBROCMD "$QUERY" - ;; - - add|rm) - MODE=$1; - - if [ "$MODE" = "add" ] ; then - ARG_NUM=3; - else - ARG_NUM=2; - fi - - if [ $# -lt $ARG_NUM ] ; then - usage_rpid - exit 1 - fi - - set_user $2 - is_user $2 - if [ $? -ne 0 ] ; then - merr "rpid - invalid user '$2'" - exit 1 - fi - shift 2 - - if [ "$MODE" = "add" ] ; then - RPID_VAL="'$1'"; - else - RPID_VAL=NULL; - fi - - QUERY="UPDATE $SUB_TABLE SET $RPID_COLUMN=$RPID_VAL \ -WHERE $SUBSCRIBER_COLUMN='$OSERUSER' AND $REALM_COLUMN='$OSERDOMAIN';" - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "rpid - SQL Error" - exit 1 - fi - - $0 rpid show "$OSERUSER@$OSERDOMAIN" - - ;; - - *) - usage_rpid - exit 1 - ;; - esac -} - -# -##### ------------------------------------------------ ##### -### SPEEDDIAL management -# -speeddial() { - if [ "$#" -lt 2 ] ; then - merr "speeddial - too few parameters" - echo - usage_speeddial - exit 1 - fi - - require_dbengine - shift - - case $1 in - list) - if [ $# -eq 2 ] ; then - # print speed-dials for user - check_aor "$2" - if [ "$?" -ne "0" ] ; then - merr "speeddial - <$2> is not a valid AoR (user@domain)" - exit 1 - fi - - set_user $2 - - CLAUSE="WHERE $SD_USER_COLUMN='$OSERUSER' AND \ -$SD_DOMAIN_COLUMN='$OSERDOMAIN'" - mecho "Dumping speed-dials for user=<$2>" - echo - QUERY="SELECT CONCAT($SD_SD_USER_COLUMN,'@',\ -$SD_SD_DOMAIN_COLUMN) AS 'Short number', $SD_NEW_URI_COLUMN AS 'New URI',\ -$SD_DESC_COLUMN FROM $SD_TABLE $CLAUSE;" - $DBROCMD "$QUERY" - #| $AWK 'BEGIN {line=0;} - # /^\+/ { next } - #{ if(line==0) print "## SpeedDial \tNew-URI \tDescription\n"; - # else { - # ORS_BAK=ORS; - # ORS=""; - # print line ") " $1 "@" $2 "\t" $3 "\t\"" $4; - # for (i=5;i<=NF;++i) print FS $i; - # ORS=ORS_BAK; - # print "\""; - # } - # line++; - #}' - elif [ $# -eq 1 ] ; then - mecho "Dumping all speed-dials may take long: do you want to proceed? [Y|N] " - read answer - if [ "$answer" = "y" -o "$answer" = "Y" ] ; then - mecho "Dumping all speed-dials..." - echo - else - exit 1 - fi - QUERY="SELECT CONCAT($SD_SD_USER_COLUMN,'@',\ -$SD_SD_DOMAIN_COLUMN) AS 'Short number', CONCAT($SD_USER_COLUMN,'@',\ -$SD_DOMAIN_COLUMN) AS 'Owner', $SD_NEW_URI_COLUMN AS 'New URI',\ -$SD_DESC_COLUMN FROM $SD_TABLE;" - $DBROCMD "$QUERY" - #| $AWK 'BEGIN {line=0;} - # /^\+/ { next } - # { line++; - #if(line==1) print "SIP-ID \tSpeedDial \tNew-URI \tDescritpion\n"; - # else { - # ORS_BAK=ORS; - # ORS=""; - # print $3 "@" $4 "\t" $1 "@" $2 "\t" $5 "\t\"" $6; - # for (i=7;i<=NF;++i) print FS $i; - # ORS=ORS_BAK; - # print "\""; - # } - # }' - else - merr "speeddial - wrong number of params for command [list]" - usage_speeddial - exit 1 - fi - - exit $? - ;; - show) - if [ $# -ne 2 ] ; then - merr "speeddial - wrong number of params for command [show]" - usage_speeddial - exit 1 - fi - - check_aor "$2" - if [ "$?" -ne "0" ] ; then - merr "speeddial - $2 is not a valid AoR (user@domain)" - exit 1 - fi - - set_user $2 - - CLAUSE="WHERE $SD_SD_USER_COLUMN='$OSERUSER' AND \ -$SD_SD_DOMAIN_COLUMN='$OSERDOMAIN'" - QUERY="SELECT CONCAT($SD_USER_COLUMN,'@',$SD_DOMAIN_COLUMN) \ -AS 'Owner', $SD_NEW_URI_COLUMN AS 'New URI', $SD_DESC_COLUMN FROM \ -$SD_TABLE $CLAUSE ; " - mecho "Details for speeddial <$2>" - $DBROCMD "$QUERY" - # | $AWK 'BEGIN {line=0;} /^\+/ { next } - # { - # if(line==0) print "## SIP-ID \tNew-URI \tDescritpion\n"; - # else { - # ORS_BAK=ORS;usage_kamailio_monitor() { - # ORS=""; - # print line ") " $1 "@" $2 "\t" $3 "\t\"" $4; - # for (i=5;i<=NF;++i) print FS $i; - # ORS=ORS_BAK; - # print "\""; - # } - # line++; - # }' - - exit $? - ;; - add) - if [ $# -ne 4 ] ; then - if [ $# -ne 5 ] ; then - merr "speeddial - wrong number of parameters" - usage_speeddial - exit 1 - fi - fi - shift - check_aor "$1" - if [ "$?" -ne "0" ] ; then - merr "speeddial - $1 is not a valid AoR (user@domain)" - exit 1 - fi - - check_aor "$2" - if [ "$?" -ne "0" ] ; then - merr "speeddial - $2 is not a valid AoR (user@domain)" - exit 1 - fi - - check_sipaor "$3" - if [ "$?" -ne "0" ] ; then - merr "speeddial - $3 is not a valid SIP AoR (sip:user@domain)" - exit 1 - fi - - set_user $1 - TMP_OSERUSER=$OSERUSER - TMP_OSERDOMAIN=$OSERDOMAIN - set_user $2 - - QUERY="INSERT INTO $SD_TABLE ($SD_USER_COLUMN,$SD_DOMAIN_COLUMN,\ -$SD_SD_USER_COLUMN,$SD_SD_DOMAIN_COLUMN,$SD_NEW_URI_COLUMN,$SD_DESC_COLUMN) \ -VALUES ('$TMP_OSERUSER','$TMP_OSERDOMAIN','$OSERUSER','$OSERDOMAIN','$3','$4');" - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "speeddial - SQL Error" - exit 1 - fi - mecho "ok - spedd dial added" - echo - exit $? - ;; - rm) - if [ $# -ne 3 ] ; then - merr "speeddial rm - invalid number of parameters" - usage_speeddial - exit 1 - fi - - shift - - check_aor "$1" - if [ "$?" -ne "0" ] ; then - merr "speeddial - $1 is not a valid AoR (user@domain)" - exit 1 - fi - - check_aor "$2" - if [ "$?" -ne "0" ] ; then - merr "speeddial - $2 is not a valid AoR (user@domain)" - exit 1 - fi - - set_user $1 - TMP_OSERUSER=$OSERUSER - TMP_OSERDOMAIN=$OSERDOMAIN - set_user $2 - - CLAUSE="WHERE $SD_USER_COLUMN='$TMP_OSERUSER' AND \ -$SD_DOMAIN_COLUMN='$TMP_OSERDOMAIN' AND $SD_SD_USER_COLUMN='$OSERUSER' AND \ -$SD_SD_DOMAIN_COLUMN='$OSERDOMAIN'" - QUERY="DELETE FROM $SD_TABLE $CLAUSE;" - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "speeddial - SQL Error" - exit 1 - fi - - mecho "ok - spedd dial deleted" - echo - - ;; - - help) - usage_speeddial - ;; - - *) - merr "speeddial - unknown command" - usage_speeddial - exit 1 - ;; - esac -} # end speed_dial() - -# -##### ------------------------------------------------ ##### -### acc management -# -acc() { - if [ "$#" -lt 2 ] ; then - merr "acc - too few parameters" - usage_acc - exit 1 - fi - shift; - require_dbengine - case $1 in - initdb) - QUERY=$(cat <<-END -ALTER TABLE acc ADD COLUMN src_user VARCHAR(64) NOT NULL DEFAULT ''; -ALTER TABLE acc ADD COLUMN src_domain VARCHAR(128) NOT NULL DEFAULT ''; -ALTER TABLE acc ADD COLUMN src_ip varchar(64) NOT NULL default ''; -ALTER TABLE acc ADD COLUMN dst_ouser VARCHAR(64) NOT NULL DEFAULT ''; -ALTER TABLE acc ADD COLUMN dst_user VARCHAR(64) NOT NULL DEFAULT ''; -ALTER TABLE acc ADD COLUMN dst_domain VARCHAR(128) NOT NULL DEFAULT ''; -ALTER TABLE missed_calls ADD COLUMN src_user VARCHAR(64) NOT NULL DEFAULT ''; -ALTER TABLE missed_calls ADD COLUMN src_domain VARCHAR(128) NOT NULL DEFAULT ''; -ALTER TABLE missed_calls ADD COLUMN src_ip varchar(64) NOT NULL default ''; -ALTER TABLE missed_calls ADD COLUMN dst_ouser VARCHAR(64) NOT NULL DEFAULT ''; -ALTER TABLE missed_calls ADD COLUMN dst_user VARCHAR(64) NOT NULL DEFAULT ''; -ALTER TABLE missed_calls ADD COLUMN dst_domain VARCHAR(128) NOT NULL DEFAULT ''; -END -) - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "error - acc db init" - exit 1 - fi - - mecho "ok - acc db init" - - ;; - - showdb) - QUERY="select * FROM $ACC_TABLE ;" - $DBROCMD "$QUERY" - ;; - - recent) - TIMENOW=`date +"%s"` - if [ $# -eq 2 ] ; then - CLAUSE=" WHERE time>=$TIMENOW - $2 " - else - CLAUSE=" WHERE time>=$TIMENOW - 300 " - fi - QUERY="select * FROM $ACC_TABLE $CLAUSE ; " - $DBROCMD "$QUERY" - ;; - - - *) - usage_acc - exit 1 - ;; - esac -} # end acc() - - -# -##### ================================================ ##### -### subscriber management -# -subscriber() { - if [ "$#" -lt 2 ] ; then - merr "too few parameters" - usage_subscriber - exit 1 - fi - - require_dbengine - - case $1 in - add) - if [ $# -ne 3 ] ; then - usage_subscriber - exit 1 - fi - shift - credentials $1 $2 - is_user $1 - if [ $? -eq 0 ] ; then - minfo "user '$1' already exists" - exit 1 - fi - set_user $1 - check_alias $OSERUSER $OSERDOMAIN - if [ "$ALIAS_EXISTS" = "1" ] ; then - minfo "user '$1' already exists as alias" - exit 1 - fi - - if [ "$STORE_PLAINTEXT_PW" = "1" ] ; then - PASS="$2" - else - PASS="" - fi - - QUERY="insert into $SUB_TABLE ($SUBSCRIBER_COLUMN,\ - $REALM_COLUMN,$HA1_COLUMN,$HA1B_COLUMN,$PASSWORD_COLUMN) \ - values ('$OSERUSER','$OSERDOMAIN','$HA1','$HA1B','$PASS');"; - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "introducing the new user '$1' to the database failed" - else - mecho "new user '$1' added" - fi - ;; - - show) - if [ $# -ne 2 ] ; then - usage_subscriber - exit 1 - fi - shift - - set_user $1 - - case $DBENGINE in - MYSQL|mysql|MySQL) - QUERY="SELECT * FROM $SUB_TABLE \ -WHERE $SUBSCRIBER_COLUMN='$OSERUSER' AND $REALM_COLUMN='$OSERDOMAIN'\G" - ;; - *) - QUERY="SELECT * FROM $SUB_TABLE \ -WHERE $SUBSCRIBER_COLUMN='$OSERUSER' AND $REALM_COLUMN='$OSERDOMAIN';" - ;; - esac - $DBROCMD "$QUERY" - ;; - - passwd) - if [ $# -ne 3 ] ; then - usage_subscriber - exit 1 - fi - shift - credentials $1 $2 - - is_user $1 - if [ $? -ne 0 ] ; then - merr "non-existent user '$1'" - exit 1 - fi - - if [ "$STORE_PLAINTEXT_PW" = "1" ] ; then - PASS="$2" - else - PASS="" - fi - - QUERY="update $SUB_TABLE set $HA1_COLUMN='$HA1', \ -$HA1B_COLUMN='$HA1B', $PASSWORD_COLUMN='$PASS' \ -WHERE $SUBSCRIBER_COLUMN='$OSERUSER' and $REALM_COLUMN='$OSERDOMAIN';" - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "password change failed" - else - minfo "password change succeeded" - fi - ;; - - rm) - if [ $# -ne 2 ] ; then - usage_subscriber - exit 1 - fi - - require_ctlengine - shift - - is_user $1 - if [ $? -ne 0 ] ; then - merr "non-existent user '$1'" - exit 1 - fi - - # begin with remove all user's privileges - acl revoke $1 > /dev/null 2>&1 - - # destroy db-aliases - QUERY="delete from $DA_TABLE where $DA_USER_COLUMN='$OSERUSER' \ -and $DA_DOMAIN_COLUMN='$OSERDOMAIN';" - $DBCMD "$QUERY" - - - # destroy the user now - QUERY="delete from $SUB_TABLE where $SUBSCRIBER_COLUMN='$OSERUSER' \ -and $REALM_COLUMN='$OSERDOMAIN';" - $DBCMD "$QUERY" - - # and also all his contacts - $0 ul rm $1 > /dev/null 2>&1 - ;; - sets) - if [ $# -ne 4 ] ; then - usage_subscriber - exit 1 - fi - shift - - is_user $1 - if [ $? -ne 0 ] ; then - merr "non-existent user '$1'" - exit 1 - fi - - QUERY="update $SUB_TABLE set $2='$3' \ -WHERE $SUBSCRIBER_COLUMN='$OSERUSER' and $REALM_COLUMN='$OSERDOMAIN';" - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "attribute change failed" - else - minfo "attribute change succeeded" - fi - ;; - setn) - if [ $# -ne 4 ] ; then - usage_subscriber - exit 1 - fi - shift - - is_user $1 - if [ $? -ne 0 ] ; then - merr "non-existent user '$1'" - exit 1 - fi - - QUERY="update $SUB_TABLE set $2=$3 \ -WHERE $SUBSCRIBER_COLUMN='$OSERUSER' and $REALM_COLUMN='$OSERDOMAIN';" - $DBCMD "$QUERY" - if [ $? -ne 0 ] ; then - merr "attribute change failed" - else - minfo "attribute change succeeded" - fi - ;; - - esac - -} - -# -##### ================================================ ##### -### USRLOC management -# -usrloc() { - if [ "$#" -lt 2 ] ; then - merr "usrloc - too few parameters" - usage_usrloc - exit 1 - fi - - require_ctlengine - - if [ "$1" = "alias" ] ; then - USRLOC_TABLE="$ALS_TABLE" - if [ -z "$USRLOC_TABLE" ] ; then - USRLOC_TABLE=aliases - fi - CHECK_SUB=1 - elif [ "$1" = "ul" ] ; then - USRLOC_TABLE="$UL_TABLE" - if [ -z "$USRLOC_TABLE" ] ; then - USRLOC_TABLE=location - fi - CHECK_SUB=0 - elif [ "$1" = "usrloc" ] ; then - USRLOC_TABLE="$UL_TABLE" - if [ -z "$USRLOC_TABLE" ] ; then - USRLOC_TABLE=location - fi - CHECK_SUB=0 - else - merr "usrloc - unknown subcommand '$1'" - usage_usrloc - exit 1 - fi - shift - - case $1 in - show) - if [ $# -eq 2 ] ; then - if [ "$2" = "--brief" ] ; then - ctl_cmd_run ul.dump brief - else - set_user $2 - ctl_cmd_run ul.lookup \ - $USRLOC_TABLE "$OSERUSER@$OSERDOMAIN" - fi - elif [ $# -eq 1 ] ; then - ctl_cmd_run ul.dump - else - merr "wrong number of params" - usage_usrloc - exit 1 - fi - exit $? - ;; - add) - if [ $# -eq 3 ] ; then - # expires 0 means persistent contact - UL_EXPIRES=0 - UL_FLAGS=0 - BR_FLAGS=0 - UL_PATH="." - elif [ $# -eq 4 ] ; then - UL_EXPIRES=$4 - UL_FLAGS=0 - BR_FLAGS=0 - UL_PATH="." - elif [ $# -eq 5 ] ; then - UL_EXPIRES=$4 - UL_FLAGS=0 - BR_FLAGS=0 - UL_PATH="$5" - else - usage_usrloc - exit 1 - fi - shift - check_uri "$2" - - if [ "$?" -ne "0" ] ; then - merr "$2 is not a valid URI" - exit 1 - fi - - set_user $1 - if [ "$CHECK_SUB" -ne 0 ] ; then - is_user $1 - if [ $? -eq 0 ] ; then - merr "overlap of alias with an existing subscriber name" - exit 1; - fi - fi - - check_alias $OSERUSER $OSERDOMAIN - if [ "$ALIAS_EXISTS" = "1" ] ; then - if [ "$CHECK_SUB" -ne 0 ] ; then - minfo "alias already defined" - else - merr "AOR is an alias" - fi - exit 1 - fi - - if [ -z "$DEFAULT_Q" ] ; then - DEFAULT_Q="1.0" - fi - - ctl_cmd_run ul.add "$USRLOC_TABLE" "$OSERUSER@$OSERDOMAIN" "$2" \ -"$UL_EXPIRES" "$DEFAULT_Q" "$UL_PATH" "$UL_FLAGS" "$BR_FLAGS" "$ALL_METHODS" - exit $? - ;; - rm) - if [ $# -eq 2 ] ; then - shift - set_user $1 - ctl_cmd_run ul.rm $USRLOC_TABLE "$OSERUSER@$OSERDOMAIN" - - elif [ $# -eq 3 ] ; then - shift - set_user $1 - check_uri "$2" - if [ "$?" -ne "0" ] ; then - merr "$2 is not a valid SIP URI (sip:[user@]domain)" - exit 1 - fi - - ctl_cmd_run ul.rm_contact $USRLOC_TABLE "$OSERUSER@$OSERDOMAIN" "$2" - - else - merr "wrong number of params" - usage_usrloc - exit 1 - fi - ;; - - dbclean) - require_dbengine - KSR_CLEAN_VAL=3600 - if [ $# -eq 2 ] ; then - KSR_CLEAN_VAL=$2 - fi - QUERY="delete from $USRLOC_TABLE where expires < SUBDATE(NOW(), INTERVAL $KSR_CLEAN_VAL SECOND);" - $DBCMD "$QUERY" - - exit $? - ;; - - *) - usage_usrloc - exit 1 - ;; - esac -} - -##### ================================================ ##### -### TLS CA management -# - -tls_ca() { - - if [ "$1" = "rootCA" ] ; then - if [ -z $2 ] ; then - # use default - CA_BASE=$ETCDIR/tls - else - CA_BASE=`(cd $2;pwd)` - fi - - if [ ! -d $CA_BASE ] ; then - merr "Config directory ($CA_BASE) does not exist" - exit 1 - fi - - CA_CONF='ca.conf' - CA_PATH=$CA_BASE/rootCA - if [ ! -f $CA_BASE/$CA_CONF ] ; then - merr "root CA config file ($CA_BASE/$CA_CONF) does not exist" - exit 1 - fi - - if [ -d $CA_PATH ] ; then - mwarn "root CA directory ($CA_PATH) exists! Remove it (y/n)?" - read X - if [ "$X" != "y" -a "$X" != "Y" ] ; then - exit 1 - fi - fi - - mecho "Creating directory $CA_PATH and its sub-tree" - mkdir -p $CA_PATH - if [ $? -ne 0 ] ; then - merr "Failed to create root directory $CA_PATH" - exit 1 - fi - rm -fr "${CA_PATH:?}"/* - mkdir $CA_PATH/private - mkdir $CA_PATH/certs - touch $CA_PATH/index.txt - echo 01 >$CA_PATH/serial - - mecho "Creating CA self-signed certificate" - ( cd $CA_PATH; openssl req -config $CA_BASE/$CA_CONF -x509 -newkey \ - rsa:2048 -days 365 -out ./cacert.pem -outform PEM ) - if [ $? -ne 0 ] ; then - merr "Failed to create self-signed certificate" - exit 1 - fi - - mecho "Protecting CA private key" - chmod 600 $CA_PATH/private/cakey.pem - - mecho "DONE" - minfo "Private key can be found in $CA_PATH/private/cakey.pem" - minfo "Certificate can be found in $CA_PATH/cacert.pem" - - elif [ "$1" = "userCERT" ] ; then - - if [ -z $2 ] ; then - merr "Missing user name parameter" - exit 1 - fi - - if [ -z $3 ] ; then - # use default - CA_BASE=$ETCDIR/tls - else - CA_BASE=`(cd $3;pwd)` - fi - - if [ ! -d $CA_BASE ] ; then - merr "Config directory ($CA_BASE) does not exist" - exit 1 - fi - - USER_DIR=$CA_BASE/$2 - USER_CFG=$CA_BASE/$2.conf - USER=$2 - REQ_CFG=$CA_BASE/request.conf - - if [ ! -f $USER_CFG ] ; then - merr "User config file $USER_CFG not found" - exit 1 - fi - - if [ ! -f $REQ_CFG ] ; then - merr "Request config file $REQ_CFG not found" - exit 1 - fi - - mecho "Using config file $USER_CFG" - - if [ -d $USER_DIR ] ; then - mwarn "User CERT directory ($USER_DIR) exists! Remove it (y/n)?" - read X - if [ "$X" != "y" -a "$X" != "Y" ] ; then - exit 1 - fi - fi - - mecho "Creating directory $USER_DIR" - mkdir -p $USER_DIR - if [ $? -ne 0 ] ; then - merr "Failed to create user directory $USER_DIR " - exit 1 - fi - rm -fr "${USER_DIR:?}"/* - - mecho "Creating user certificate request" - openssl req -config $USER_CFG -out $USER_DIR/$USER-cert_req.pem \ - -keyout $USER_DIR/$USER-privkey.pem -new -nodes - if [ $? -ne 0 ] ; then - merr "Failed to generate certificate request" - exit 1 - fi - - mecho "Signing certificate request" - ( cd $CA_BASE ; openssl ca -config $REQ_CFG -in \ - $USER_DIR/$USER-cert_req.pem -out $USER_DIR/$USER-cert.pem ) - if [ $? -ne 0 ] ; then - merr "Failed to generate certificate request" - exit 1 - fi - - mecho "Generating CA list" - cat $CA_BASE/rootCA/cacert.pem >> $USER_DIR/$USER-calist.pem - - mecho "DONE" - minfo "Private key is locate at $USER_DIR/$USER-privkey.pem " - minfo "Certificate is locate at $USER_DIR/$USER-cert.pem " - minfo "CA-List is locate at $USER_DIR/$USER-calist.pem " - - else - merr "unknown TLS command $1" - usage_tls - exit 1 - fi -} - -extcmd() { - if [ -f $ETCDIR/kamctl.${1}.ext ]; then - . $ETCDIR/kamctl.${1}.ext - else - if [ -f ~/.kamctl/kamctl.${1}.ext ]; then - . ~/.kamctl/kamctl.${1}.ext - else - return - fi - fi - - XCMD=cmd_${1} - - shift - $XCMD "$@" - - exit 1 -} - -##### ================================================ ##### -### trap with gdb kamailio processes using RPC core.psx -# - -kamailio_trap() { - if [ -z "$GDB" ] ; then - merr "'gdb' tool not found: set GDB variable to correct tool path" - exit - fi - DATE=`/bin/date +%Y%m%d_%H%M%S` - LOG_FILE=/tmp/gdb_kamailio_${DATE}.txt - minfo "Trap file: $LOG_FILE" - ctl_cmd_run core.psx > $LOG_FILE - echo -n "Trapping Kamailio with gdb: " - PID_TIMESTAMP_VECTOR=`$EGREP 'PID' $LOG_FILE | $EGREP -Eo '[0-9]+'` - for pid in $PID_TIMESTAMP_VECTOR - do - echo -n "." - PID=`echo $pid | cut -d '-' -f 1` - echo "" >> $LOG_FILE - echo "---start $PID -----------------------------------------------------" >> $LOG_FILE - $GDB kamailio $PID -batch --eval-command="bt full" >> $LOG_FILE 2>&1 - echo "---end $PID -------------------------------------------------------" >> $LOG_FILE - done - echo "." -} - -##### ================================================ ##### -### trap with gdb kamailio processes using ps command -# - -kamailio_pstrap() { - if [ -z "$GDB" ] ; then - merr "'gdb' tool not found: set GDB variable to correct tool path" - exit - fi - DATE=`/bin/date +%Y%m%d_%H%M%S` - LOG_FILE=/tmp/gdb_kamailio_${DATE}.txt - minfo "Trap file: $LOG_FILE" - ps axw | grep kamailio | grep -v grep | grep -v kamctl | sort > $LOG_FILE - echo "" >> $LOG_FILE - echo "" >> $LOG_FILE - echo -n "Trapping Kamailio with gdb: " - PID_TIMESTAMP_VECTOR=`ps axw | grep kamailio | grep -v grep | grep -v kamctl | sort | awk '{print $1}'` - for pid in $PID_TIMESTAMP_VECTOR - do - echo -n "." - PID=`echo $pid | cut -d '-' -f 1` - echo "" >> $LOG_FILE - echo "---start $PID -----------------------------------------------------" >> $LOG_FILE - $GDB kamailio $PID -batch --eval-command="p process_no" --eval-command="p pt[process_no]" --eval-command="bt full" >> $LOG_FILE 2>&1 - echo "---end $PID -------------------------------------------------------" >> $LOG_FILE - done - echo "." -} - -# -##### ================================================ ##### -### main command switch -# -case $1 in - acl) - shift - acl "$@" - ;; - - add) - subscriber "$@" - ;; - - show) - subscriber "$@" - ;; - - passwd) - subscriber "$@" - ;; - - rm) - subscriber "$@" - ;; - - sets) - subscriber "$@" - ;; - - setn) - subscriber "$@" - ;; - - alias|ul|usrloc) - usrloc "$@" - ;; - - alias_db|aliasdb) - alias_db "$@" - ;; - - avp) - avpops "$@" - ;; - - cisco_restart) - if [ "$#" -ne 2 ] ; then - usage_cisco_restart - exit 1 - fi - cisco_restart $2 - ;; - - db) - shift - db_ops "$@" - ;; - - showdb|userdb) - usage - exit 1 - ;; - - domain) - shift - domain "$@" - ;; - - uid_domain) - shift - uid_domain "$@" - ;; - - trusted) - shift - permissions_trusted "$@" - ;; - - address) - shift - permissions_address "$@" - ;; - - mtree) - shift - mtree_management "$@" - ;; - - rpc) - require_ctlengine - shift - $CTLCMD "$@" - ;; - - rpcprint) - require_ctlengine - shift - $CTLCMDPRINT "$@" - ;; - - ser|sercmd|kamcmd) - require_kamcmd - shift - $SERCTLCMD "$@" - ;; - - lcr) - shift - lcr "$@" - ;; - - cr) - shift - cr "$@" - ;; - - dispatcher) - shift - dispatcher "$@" - ;; - - dialog) - shift - dialog "$@" - ;; - - dialplan) - shift - dialplan "$@" - ;; - - monitor|console|moni|con) - require_ctlengine - $KAMAILIO_MONITOR "$@" - ;; - - online) - require_ctlengine - ctl_cmd_run ul.dump brief | $EGREP -i aor | $EGREP -v AoRs \ - | awk '{print $2}' | sed 's/"//g' | sort | sort -mu - exit $? - ;; - - ping) - # error handling is hacked -- filter_fl should not - # consume positive status -- that should be done by - # calling app - if [ "$#" -ne 2 ] ; then - usage_ping - exit 1 - fi - options_ping $2 - ;; - - ps) - require_ctlengine - ctl_cmd_run core.psx - ;; - - psa) - require_ctlengine - ctl_cmd_run core.psa - ;; - - uptime) - require_ctlengine - ctl_cmd_run core.uptime - ;; - - stats) - require_ctlengine - if [ "$#" -eq 1 ] ; then - ctl_cmd_run stats.get_statistics all - else - ctl_cmd_run stats.get_statistics "${2}:" - fi - ;; - - srv) - shift - ksr_srv "$@" - ;; - - restart) - kamailio_stop - sleep 2 - kamailio_start - ;; - - rpid) - rpid "$@" - ;; - - speeddial|speed_dial) - speeddial "$@" - ;; - - acc) - acc "$@" - ;; - - tls) - shift - tls_ca "$@" - ;; - - trap) - require_ctlengine - kamailio_trap - ;; - - pstrap) - kamailio_pstrap - ;; - - start) - kamailio_start - ;; - - stop) - kamailio_stop - ;; - - version) - echo "$0 $VERSION" - ;; - - *) - extcmd "$@" - - usage - exit 1 - ;; -esac -