00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "asterisk.h"
00027
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 211528 $")
00029
00030 #include <unistd.h>
00031 #include <stdlib.h>
00032 #include <string.h>
00033 #include <stdio.h>
00034 #include <netdb.h>
00035 #include <netinet/in.h>
00036 #include <netinet/in_systm.h>
00037 #include <netinet/ip.h>
00038 #include <sys/socket.h>
00039
00040 #include "asterisk/config.h"
00041 #include "asterisk/logger.h"
00042 #include "asterisk/cli.h"
00043 #include "asterisk/lock.h"
00044 #include "asterisk/frame.h"
00045 #include "asterisk/options.h"
00046 #include "asterisk/md5.h"
00047 #include "asterisk/astdb.h"
00048 #include "asterisk/utils.h"
00049 #include "asterisk/acl.h"
00050 #include "iax2.h"
00051 #include "iax2-provision.h"
00052 #include "iax2-parser.h"
00053
00054 #ifndef IPTOS_MINCOST
00055 #define IPTOS_MINCOST 0x02
00056 #endif
00057
00058 static int provinit = 0;
00059
00060 struct iax_template {
00061 int dead;
00062 char name[80];
00063 char src[80];
00064 struct iax_template *next;
00065 char user[20];
00066 char pass[20];
00067 char lang[10];
00068 unsigned short port;
00069 unsigned int server;
00070 unsigned short serverport;
00071 unsigned int altserver;
00072 unsigned int flags;
00073 unsigned int format;
00074 unsigned int tos;
00075 } *templates;
00076
00077 static struct iax_flag {
00078 char *name;
00079 int value;
00080 } iax_flags[] = {
00081 { "register", PROV_FLAG_REGISTER },
00082 { "secure", PROV_FLAG_SECURE },
00083 { "heartbeat", PROV_FLAG_HEARTBEAT },
00084 { "debug", PROV_FLAG_DEBUG },
00085 { "disablecid", PROV_FLAG_DIS_CALLERID },
00086 { "disablecw", PROV_FLAG_DIS_CALLWAIT },
00087 { "disablecidcw", PROV_FLAG_DIS_CIDCW },
00088 { "disable3way", PROV_FLAG_DIS_THREEWAY },
00089 };
00090
00091 char *iax_provflags2str(char *buf, int buflen, unsigned int flags)
00092 {
00093 int x;
00094
00095 if (!buf || buflen < 1)
00096 return NULL;
00097
00098 buf[0] = '\0';
00099
00100 for (x = 0; x < sizeof(iax_flags) / sizeof(iax_flags[0]); x++) {
00101 if (flags & iax_flags[x].value){
00102 strncat(buf, iax_flags[x].name, buflen - strlen(buf) - 1);
00103 strncat(buf, ",", buflen - strlen(buf) - 1);
00104 }
00105 }
00106
00107 if (!ast_strlen_zero(buf))
00108 buf[strlen(buf) - 1] = '\0';
00109 else
00110 strncpy(buf, "none", buflen - 1);
00111
00112 return buf;
00113 }
00114
00115 static unsigned int iax_str2flags(const char *buf)
00116 {
00117 int x;
00118 int len;
00119 int found;
00120 unsigned int flags = 0;
00121 char *e;
00122 while(buf && *buf) {
00123 e = strchr(buf, ',');
00124 if (e)
00125 len = e - buf;
00126 else
00127 len = 0;
00128 found = 0;
00129 for (x=0;x<sizeof(iax_flags) / sizeof(iax_flags[0]); x++) {
00130 if ((len && !strncasecmp(iax_flags[x].name, buf, len)) ||
00131 (!len && !strcasecmp(iax_flags[x].name, buf))) {
00132 flags |= iax_flags[x].value;
00133 break;
00134 }
00135 }
00136 if (e) {
00137 buf = e + 1;
00138 while(*buf && (*buf < 33))
00139 buf++;
00140 } else
00141 break;
00142 }
00143 return flags;
00144 }
00145 AST_MUTEX_DEFINE_STATIC(provlock);
00146
00147 static struct iax_template *iax_template_find(const char *s, int allowdead)
00148 {
00149 struct iax_template *cur;
00150 cur = templates;
00151 while(cur) {
00152 if (!strcasecmp(s, cur->name)) {
00153 if (!allowdead && cur->dead)
00154 cur = NULL;
00155 break;
00156 }
00157 cur = cur->next;
00158 }
00159 return cur;
00160 }
00161
00162 char *iax_prov_complete_template(const char *line, const char *word, int pos, int state)
00163 {
00164 struct iax_template *c;
00165 int which=0;
00166 char *ret = NULL;
00167 int wordlen = strlen(word);
00168
00169 ast_mutex_lock(&provlock);
00170 for (c = templates; c; c = c->next) {
00171 if (!strncasecmp(word, c->name, wordlen) && ++which > state) {
00172 ret = strdup(c->name);
00173 break;
00174 }
00175 }
00176 ast_mutex_unlock(&provlock);
00177
00178 return ret;
00179 }
00180
00181 static unsigned int prov_ver_calc(struct iax_ie_data *provdata)
00182 {
00183 struct MD5Context md5;
00184 unsigned int tmp[4];
00185 MD5Init(&md5);
00186 MD5Update(&md5, provdata->buf, provdata->pos);
00187 MD5Final((unsigned char *)tmp, &md5);
00188 return tmp[0] ^ tmp[1] ^ tmp[2] ^ tmp[3];
00189 }
00190
00191 int iax_provision_build(struct iax_ie_data *provdata, unsigned int *signature, const char *template, int force)
00192 {
00193 struct iax_template *cur;
00194 unsigned int sig;
00195 char tmp[40];
00196 memset(provdata, 0, sizeof(*provdata));
00197 ast_mutex_lock(&provlock);
00198 cur = iax_template_find(template, 1);
00199
00200 if (!cur)
00201 cur = iax_template_find("*", 1);
00202 if (cur) {
00203
00204 if (force || strlen(cur->user))
00205 iax_ie_append_str(provdata, PROV_IE_USER, cur->user);
00206 if (force || strlen(cur->pass))
00207 iax_ie_append_str(provdata, PROV_IE_PASS, cur->pass);
00208 if (force || strlen(cur->lang))
00209 iax_ie_append_str(provdata, PROV_IE_LANG, cur->lang);
00210 if (force || cur->port)
00211 iax_ie_append_short(provdata, PROV_IE_PORTNO, cur->port);
00212 if (force || cur->server)
00213 iax_ie_append_int(provdata, PROV_IE_SERVERIP, cur->server);
00214 if (force || cur->serverport)
00215 iax_ie_append_short(provdata, PROV_IE_SERVERPORT, cur->serverport);
00216 if (force || cur->altserver)
00217 iax_ie_append_int(provdata, PROV_IE_ALTSERVER, cur->altserver);
00218 if (force || cur->flags)
00219 iax_ie_append_int(provdata, PROV_IE_FLAGS, cur->flags);
00220 if (force || cur->format)
00221 iax_ie_append_int(provdata, PROV_IE_FORMAT, cur->format);
00222 if (force || cur->tos)
00223 iax_ie_append_byte(provdata, PROV_IE_TOS, cur->tos);
00224
00225
00226 sig = prov_ver_calc(provdata);
00227 if (signature)
00228 *signature = sig;
00229
00230 iax_ie_append_int(provdata, PROV_IE_PROVVER, sig);
00231
00232 snprintf(tmp, sizeof(tmp), "v0x%08x", sig);
00233 ast_db_put("iax/provisioning/cache", template, tmp);
00234 } else
00235 ast_db_put("iax/provisioning/cache", template, "u");
00236 ast_mutex_unlock(&provlock);
00237 return cur ? 0 : -1;
00238 }
00239
00240 int iax_provision_version(unsigned int *version, const char *template, int force)
00241 {
00242 char tmp[80] = "";
00243 struct iax_ie_data ied;
00244 int ret=0;
00245 memset(&ied, 0, sizeof(ied));
00246
00247 ast_mutex_lock(&provlock);
00248 ast_db_get("iax/provisioning/cache", template, tmp, sizeof(tmp));
00249 if (sscanf(tmp, "v%30x", version) != 1) {
00250 if (strcmp(tmp, "u")) {
00251 ret = iax_provision_build(&ied, version, template, force);
00252 if (ret)
00253 ast_log(LOG_DEBUG, "Unable to create provisioning packet for '%s'\n", template);
00254 } else
00255 ret = -1;
00256 } else if (option_debug)
00257 ast_log(LOG_DEBUG, "Retrieved cached version '%s' = '%08x'\n", tmp, *version);
00258 ast_mutex_unlock(&provlock);
00259 return ret;
00260 }
00261
00262 static int iax_template_parse(struct iax_template *cur, struct ast_config *cfg, const char *s, const char *def)
00263 {
00264 struct ast_variable *v;
00265 int foundportno = 0;
00266 int foundserverportno = 0;
00267 int x;
00268 struct in_addr ia;
00269 struct hostent *hp;
00270 struct ast_hostent h;
00271 struct iax_template *src, tmp;
00272 const char *t;
00273 if (def) {
00274 t = ast_variable_retrieve(cfg, s ,"template");
00275 src = NULL;
00276 if (t && strlen(t)) {
00277 src = iax_template_find(t, 0);
00278 if (!src)
00279 ast_log(LOG_WARNING, "Unable to find base template '%s' for creating '%s'. Trying '%s'\n", t, s, def);
00280 else
00281 def = t;
00282 }
00283 if (!src) {
00284 src = iax_template_find(def, 0);
00285 if (!src)
00286 ast_log(LOG_WARNING, "Unable to locate default base template '%s' for creating '%s', omitting.\n", def, s);
00287 }
00288 if (!src)
00289 return -1;
00290 ast_mutex_lock(&provlock);
00291
00292 memcpy(&tmp, cur, sizeof(tmp));
00293
00294 memcpy(cur, src, sizeof(tmp));
00295
00296 memcpy(cur->name, tmp.name, sizeof(cur->name));
00297 cur->dead = tmp.dead;
00298 cur->next = tmp.next;
00299 ast_mutex_unlock(&provlock);
00300 }
00301 if (def)
00302 strncpy(cur->src, def, sizeof(cur->src) - 1);
00303 else
00304 cur->src[0] = '\0';
00305 v = ast_variable_browse(cfg, s);
00306 while(v) {
00307 if (!strcasecmp(v->name, "port") || !strcasecmp(v->name, "serverport")) {
00308 if ((sscanf(v->value, "%5d", &x) == 1) && (x > 0) && (x < 65535)) {
00309 if (!strcasecmp(v->name, "port")) {
00310 cur->port = x;
00311 foundportno = 1;
00312 } else {
00313 cur->serverport = x;
00314 foundserverportno = 1;
00315 }
00316 } else
00317 ast_log(LOG_WARNING, "Ignoring invalid %s '%s' for '%s' at line %d\n", v->name, v->value, s, v->lineno);
00318 } else if (!strcasecmp(v->name, "server") || !strcasecmp(v->name, "altserver")) {
00319 hp = ast_gethostbyname(v->value, &h);
00320 if (hp) {
00321 memcpy(&ia, hp->h_addr, sizeof(ia));
00322 if (!strcasecmp(v->name, "server"))
00323 cur->server = ntohl(ia.s_addr);
00324 else
00325 cur->altserver = ntohl(ia.s_addr);
00326 } else
00327 ast_log(LOG_WARNING, "Ignoring invalid %s '%s' for '%s' at line %d\n", v->name, v->value, s, v->lineno);
00328 } else if (!strcasecmp(v->name, "codec")) {
00329 if ((x = ast_getformatbyname(v->value)) > 0) {
00330 cur->format = x;
00331 } else
00332 ast_log(LOG_WARNING, "Ignoring invalid codec '%s' for '%s' at line %d\n", v->value, s, v->lineno);
00333 } else if (!strcasecmp(v->name, "tos")) {
00334 if (ast_str2tos(v->value, &cur->tos))
00335 ast_log(LOG_WARNING, "Invalid tos value at line %d, see doc/ip-tos.txt for more information.\n", v->lineno);
00336 } else if (!strcasecmp(v->name, "user")) {
00337 strncpy(cur->user, v->value, sizeof(cur->user) - 1);
00338 if (strcmp(cur->user, v->value))
00339 ast_log(LOG_WARNING, "Truncating username from '%s' to '%s' for '%s' at line %d\n", v->value, cur->user, s, v->lineno);
00340 } else if (!strcasecmp(v->name, "pass")) {
00341 strncpy(cur->pass, v->value, sizeof(cur->pass) - 1);
00342 if (strcmp(cur->pass, v->value))
00343 ast_log(LOG_WARNING, "Truncating password from '%s' to '%s' for '%s' at line %d\n", v->value, cur->pass, s, v->lineno);
00344 } else if (!strcasecmp(v->name, "language")) {
00345 strncpy(cur->lang, v->value, sizeof(cur->lang) - 1);
00346 if (strcmp(cur->lang, v->value))
00347 ast_log(LOG_WARNING, "Truncating language from '%s' to '%s' for '%s' at line %d\n", v->value, cur->lang, s, v->lineno);
00348 } else if (!strcasecmp(v->name, "flags")) {
00349 cur->flags = iax_str2flags(v->value);
00350 } else if (!strncasecmp(v->name, "flags", 5) && strchr(v->name, '+')) {
00351 cur->flags |= iax_str2flags(v->value);
00352 } else if (!strncasecmp(v->name, "flags", 5) && strchr(v->name, '-')) {
00353 cur->flags &= ~iax_str2flags(v->value);
00354 } else if (strcasecmp(v->name, "template")) {
00355 ast_log(LOG_WARNING, "Unknown keyword '%s' in definition of '%s' at line %d\n", v->name, s, v->lineno);
00356 }
00357 v = v->next;
00358 }
00359 if (!foundportno)
00360 cur->port = IAX_DEFAULT_PORTNO;
00361 if (!foundserverportno)
00362 cur->serverport = IAX_DEFAULT_PORTNO;
00363 return 0;
00364 }
00365
00366 static int iax_process_template(struct ast_config *cfg, char *s, char *def)
00367 {
00368
00369 struct iax_template *cur;
00370 int mallocd = 0;
00371 cur = templates;
00372 while(cur) {
00373 if (!strcasecmp(cur->name, s))
00374 break;
00375 cur = cur->next;
00376 }
00377 if (!cur) {
00378 mallocd = 1;
00379 cur = malloc(sizeof(struct iax_template));
00380 if (!cur) {
00381 ast_log(LOG_WARNING, "Out of memory!\n");
00382 return -1;
00383 }
00384
00385 memset(cur, 0, sizeof(*cur));
00386 strncpy(cur->name, s, sizeof(cur->name) - 1);
00387 cur->dead = 1;
00388 }
00389 if (!iax_template_parse(cur, cfg, s, def))
00390 cur->dead = 0;
00391
00392
00393 if (mallocd) {
00394 ast_mutex_lock(&provlock);
00395 cur->next = templates;
00396 templates = cur;
00397 ast_mutex_unlock(&provlock);
00398 }
00399 return 0;
00400 }
00401
00402 static char show_provisioning_usage[] =
00403 "Usage: iax list provisioning [template]\n"
00404 " Lists all known IAX provisioning templates or a\n"
00405 " specific one if specified.\n";
00406
00407 static const char *ifthere(const char *s)
00408 {
00409 if (strlen(s))
00410 return s;
00411 else
00412 return "<unspecified>";
00413 }
00414
00415 static const char *iax_server(unsigned int addr)
00416 {
00417 struct in_addr ia;
00418
00419 if (!addr)
00420 return "<unspecified>";
00421
00422 ia.s_addr = htonl(addr);
00423
00424 return ast_inet_ntoa(ia);
00425 }
00426
00427
00428 static int iax_show_provisioning(int fd, int argc, char *argv[])
00429 {
00430 struct iax_template *cur;
00431 char server[INET_ADDRSTRLEN];
00432 char alternate[INET_ADDRSTRLEN];
00433 char flags[80];
00434 int found = 0;
00435 if ((argc != 3) && (argc != 4))
00436 return RESULT_SHOWUSAGE;
00437 ast_mutex_lock(&provlock);
00438 for (cur = templates;cur;cur = cur->next) {
00439 if ((argc == 3) || (!strcasecmp(argv[3], cur->name))) {
00440 if (found)
00441 ast_cli(fd, "\n");
00442 ast_copy_string(server, iax_server(cur->server), sizeof(server));
00443 ast_copy_string(alternate, iax_server(cur->altserver), sizeof(alternate));
00444 ast_cli(fd, "== %s ==\n", cur->name);
00445 ast_cli(fd, "Base Templ: %s\n", strlen(cur->src) ? cur->src : "<none>");
00446 ast_cli(fd, "Username: %s\n", ifthere(cur->user));
00447 ast_cli(fd, "Secret: %s\n", ifthere(cur->pass));
00448 ast_cli(fd, "Language: %s\n", ifthere(cur->lang));
00449 ast_cli(fd, "Bind Port: %d\n", cur->port);
00450 ast_cli(fd, "Server: %s\n", server);
00451 ast_cli(fd, "Server Port: %d\n", cur->serverport);
00452 ast_cli(fd, "Alternate: %s\n", alternate);
00453 ast_cli(fd, "Flags: %s\n", iax_provflags2str(flags, sizeof(flags), cur->flags));
00454 ast_cli(fd, "Format: %s\n", ast_getformatname(cur->format));
00455 ast_cli(fd, "TOS: 0x%x\n", cur->tos);
00456 found++;
00457 }
00458 }
00459 ast_mutex_unlock(&provlock);
00460 if (!found) {
00461 if (argc == 3)
00462 ast_cli(fd, "No provisioning templates found\n");
00463 else
00464 ast_cli(fd, "No provisioning template matching '%s' found\n", argv[3]);
00465 }
00466 return RESULT_SUCCESS;
00467 }
00468
00469 static struct ast_cli_entry cli_iax2_provision[] = {
00470 { { "iax2", "show", "provisioning", NULL },
00471 iax_show_provisioning, "Display iax provisioning",
00472 show_provisioning_usage, iax_prov_complete_template, },
00473 };
00474
00475 static int iax_provision_init(void)
00476 {
00477 ast_cli_register_multiple(cli_iax2_provision, sizeof(cli_iax2_provision) / sizeof(struct ast_cli_entry));
00478 provinit = 1;
00479 return 0;
00480 }
00481
00482 int iax_provision_unload(void)
00483 {
00484 provinit = 0;
00485 ast_cli_unregister_multiple(cli_iax2_provision, sizeof(cli_iax2_provision) / sizeof(struct ast_cli_entry));
00486 return 0;
00487 }
00488
00489 int iax_provision_reload(void)
00490 {
00491 struct ast_config *cfg;
00492 struct iax_template *cur, *prev, *next;
00493 char *cat;
00494 int found = 0;
00495 if (!provinit)
00496 iax_provision_init();
00497
00498 cur = templates;
00499 while(cur) {
00500 cur->dead = 1;
00501 cur = cur->next;
00502 }
00503 cfg = ast_config_load("iaxprov.conf");
00504 if (cfg) {
00505
00506 cat = ast_category_browse(cfg, NULL);
00507 while(cat) {
00508 if (strcasecmp(cat, "general")) {
00509 iax_process_template(cfg, cat, found ? "default" : NULL);
00510 found++;
00511 if (option_verbose > 2)
00512 ast_verbose(VERBOSE_PREFIX_3 "Loaded provisioning template '%s'\n", cat);
00513 }
00514 cat = ast_category_browse(cfg, cat);
00515 }
00516 ast_config_destroy(cfg);
00517 } else
00518 ast_log(LOG_NOTICE, "No IAX provisioning configuration found, IAX provisioning disabled.\n");
00519 ast_mutex_lock(&provlock);
00520
00521 prev = NULL;
00522 cur = templates;
00523 while(cur) {
00524 next = cur->next;
00525 if (cur->dead) {
00526 if (prev)
00527 prev->next = next;
00528 else
00529 templates = next;
00530 free(cur);
00531 } else
00532 prev = cur;
00533 cur = next;
00534 }
00535 ast_mutex_unlock(&provlock);
00536
00537 ast_db_deltree("iax/provisioning/cache", NULL);
00538 return 0;
00539
00540 }