From 38ea72559b8f580943046382e657faf03c84b3dd Mon Sep 17 00:00:00 2001 From: Mark Spencer Date: Wed, 12 Nov 2003 18:23:09 +0000 Subject: [PATCH] Backport to iax git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@1730 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- channels/Makefile | 7 ++ channels/chan_iax.c | 287 +++++++++++++++++++++++++++++++++++--------- 2 files changed, 239 insertions(+), 55 deletions(-) diff --git a/channels/Makefile b/channels/Makefile index c297992b06..dfef659815 100755 --- a/channels/Makefile +++ b/channels/Makefile @@ -113,6 +113,13 @@ else $(CC) $(SOLINK) -o $@ chan_iax2.o iax2-parser.o endif +chan_iax.so: chan_iax.o +ifeq ($(USE_MYSQL_FRIENDS),1) + $(CC) $(SOLINK) -o $@ chan_iax.o -lmysqlclient -lz +else + $(CC) $(SOLINK) -o $@ chan_iax.o +endif + chan_zap.o: $(CHANZAP) $(CC) -c $(CFLAGS) -o chan_zap.o $(CHANZAP) diff --git a/channels/chan_iax.c b/channels/chan_iax.c index d1c8394260..ed9a8af3c4 100755 --- a/channels/chan_iax.c +++ b/channels/chan_iax.c @@ -44,6 +44,10 @@ #include #include +#ifdef MYSQL_FRIENDS +#include +#endif + #include "iax.h" #ifndef IPTOS_MINCOST @@ -68,6 +72,15 @@ /* Sample over last 100 units to determine historic jitter */ #define GAMMA (0.01) +#ifdef MYSQL_FRIENDS +static ast_mutex_t mysqllock = AST_MUTEX_INITIALIZER; +static MYSQL *mysql; +static char mydbuser[80]; +static char mydbpass[80]; +static char mydbhost[80]; +static char mydbname[80]; +#endif + static char *desc = "Inter Asterisk eXchange"; static char *tdesc = "Inter Asterisk eXchange Drver"; static char *type = "IAX"; @@ -167,7 +180,6 @@ struct iax_peer { /* Dynamic Registration fields */ int dynamic; /* If this is a dynamic peer */ struct sockaddr_in defaddr; /* Default address if there is one */ - char challenge[80]; /* Challenge used to authenticate the secret */ char methods[80]; char inkeys[80]; /* Key(s) this peer can use to authenticate to us */ @@ -1502,6 +1514,92 @@ static int iax_fixup(struct ast_channel *oldchannel, struct ast_channel *newchan return 0; } +#ifdef MYSQL_FRIENDS + +static void mysql_update_peer(char *peer, struct sockaddr_in *sin) +{ + if (mysql && (strlen(peer) < 128)) { + char query[512]; + char *name; + time_t nowtime; + name = alloca(strlen(peer) * 2 + 1); + time(&nowtime); + mysql_real_escape_string(mysql, name, peer, strlen(peer)); + snprintf(query, sizeof(query), "UPDATE iax1friends SET ipaddr=\"%s\", port=\"%d\", regseconds=\"%ld\" WHERE name=\"%s\"", + inet_ntoa(sin->sin_addr), ntohs(sin->sin_port), nowtime, name); + ast_mutex_lock(&mysqllock); + if (mysql_real_query(mysql, query, strlen(query))) + ast_log(LOG_WARNING, "Unable to update database\n"); + + ast_mutex_unlock(&mysqllock); + } +} + +static struct iax_peer *mysql_peer(char *peer) +{ + struct iax_peer *p; + int success = 0; + + p = malloc(sizeof(struct iax_peer)); + memset(p, 0, sizeof(struct iax_peer)); + if (mysql && (strlen(peer) < 128)) { + char query[512]; + char *name; + int numfields, x; + int port; + time_t regseconds, nowtime; + MYSQL_RES *result; + MYSQL_FIELD *fields; + MYSQL_ROW rowval; + name = alloca(strlen(peer) * 2 + 1); + mysql_real_escape_string(mysql, name, peer, strlen(peer)); + snprintf(query, sizeof(query), "SELECT * FROM iax1friends WHERE name=\"%s\"", name); + ast_mutex_lock(&mysqllock); + mysql_query(mysql, query); + if ((result = mysql_store_result(mysql))) { + if ((rowval = mysql_fetch_row(result))) { + numfields = mysql_num_fields(result); + fields = mysql_fetch_fields(result); + success = 1; + for (x=0;xsecret, rowval[x], sizeof(p->secret)); + } else if (!strcasecmp(fields[x].name, "context")) { + strncpy(p->context, rowval[x], sizeof(p->context) - 1); + } else if (!strcasecmp(fields[x].name, "ipaddr")) { + inet_aton(rowval[x], &p->addr.sin_addr); + } else if (!strcasecmp(fields[x].name, "port")) { + if (sscanf(rowval[x], "%i", &port) != 1) + port = 0; + p->addr.sin_port = htons(port); + } else if (!strcasecmp(fields[x].name, "regseconds")) { + if (sscanf(rowval[x], "%li", ®seconds) != 1) + regseconds = 0; + } + } + } + time(&nowtime); + if ((nowtime - regseconds) > AST_DEFAULT_REG_EXPIRE) + memset(&p->addr, 0, sizeof(p->addr)); + } + } + ast_mutex_unlock(&mysqllock); + } + if (!success) { + free(p); + p = NULL; + } else { + strncpy(p->name, peer, sizeof(p->name) - 1); + p->dynamic = 1; + p->delme = 1; + p->capability = iax_capability; + strcpy(p->methods, "md5,plaintext"); + } + return p; +} +#endif /* MYSQL_FRIENDS */ + static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, int *maxtime, char *peer, char *context) { struct hostent *hp; @@ -1516,29 +1614,39 @@ static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, i p = peerl.peers; while(p) { if (!strcasecmp(p->name, peer)) { - found++; - if (capability) - *capability = p->capability; - if ((p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) && - (!p->maxms || ((p->lastms > 0) && (p->lastms <= p->maxms)))) { - if (sendani) - *sendani = p->sendani; /* Whether we transmit ANI */ - if (maxtime) - *maxtime = p->maxms; /* Max time they should take */ - if (context) - strncpy(context, p->context, AST_MAX_EXTENSION - 1); - if (p->addr.sin_addr.s_addr) { - sin->sin_addr = p->addr.sin_addr; - sin->sin_port = p->addr.sin_port; - } else { - sin->sin_addr = p->defaddr.sin_addr; - sin->sin_port = p->defaddr.sin_port; - } - break; - } + break; } p = p->next; } +#ifdef MYSQL_FRIENDS + if (!p) + p = mysql_peer(peer); +#endif + if (p) { + found++; + if (capability) + *capability = p->capability; + if ((p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) && + (!p->maxms || ((p->lastms > 0) && (p->lastms <= p->maxms)))) { + if (sendani) + *sendani = p->sendani; /* Whether we transmit ANI */ + if (maxtime) + *maxtime = p->maxms; /* Max time they should take */ + if (context) + strncpy(context, p->context, AST_MAX_EXTENSION - 1); + if (p->addr.sin_addr.s_addr) { + sin->sin_addr = p->addr.sin_addr; + sin->sin_port = p->addr.sin_port; + } else { + sin->sin_addr = p->defaddr.sin_addr; + sin->sin_port = p->defaddr.sin_port; + } + } else { + if (p->delme) + free(p); + p = NULL; + } + } ast_mutex_unlock(&peerl.lock); if (!p && !found) { hp = gethostbyname(peer); @@ -1552,8 +1660,9 @@ static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, i } } else if (!p) return -1; - else - return 0; + if (p->delme) + free(p); + return 0; } static int auto_congest(void *nothing) @@ -2699,6 +2808,10 @@ static int register_verify(int callno, struct sockaddr_in *sin, char *orequest) if (!strcasecmp(p->name, peer)) break; +#ifdef MYSQL_FRIENDS + if (!p) + p = mysql_peer(peer); +#endif if (!p) { ast_log(LOG_NOTICE, "No registration for peer '%s' (from %s)\n", peer, inet_ntoa(sin->sin_addr)); return -1; @@ -2706,17 +2819,21 @@ static int register_verify(int callno, struct sockaddr_in *sin, char *orequest) if (!p->dynamic) { ast_log(LOG_NOTICE, "Peer '%s' is not dynamic (from %s)\n", peer, inet_ntoa(sin->sin_addr)); + if (p->delme) + free(p); return -1; } if (!ast_apply_ha(p->ha, sin)) { ast_log(LOG_NOTICE, "Host %s denied access to register peer '%s'\n", inet_ntoa(sin->sin_addr), p->name); + if (p->delme) + free(p); return -1; } strncpy(iaxs[callno]->secret, p->secret, sizeof(iaxs[callno]->secret)-1); strncpy(iaxs[callno]->inkeys, p->inkeys, sizeof(iaxs[callno]->inkeys)-1); /* Check secret against what we have on file */ - if (strlen(rsasecret) && strstr(p->methods, "rsa") && strlen(p->challenge)) { + if (strlen(rsasecret) && strstr(p->methods, "rsa") && strlen(iaxs[callno]->challenge)) { if (strlen(p->inkeys)) { char tmpkeys[256]; char *stringp=NULL; @@ -2725,7 +2842,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, char *orequest) keyn = strsep(&stringp, ":"); while(keyn) { key = ast_key_get(keyn, AST_KEY_PUBLIC); - if (key && !ast_check_signature(key, p->challenge, rsasecret)) { + if (key && !ast_check_signature(key, iaxs[callno]->challenge, rsasecret)) { iaxs[callno]->state |= IAX_STATE_AUTHENTICATED; break; } else if (!key) @@ -2734,41 +2851,53 @@ static int register_verify(int callno, struct sockaddr_in *sin, char *orequest) } if (!keyn) { ast_log(LOG_NOTICE, "Host %s failed RSA authentication with inkeys '%s'\n", peer, p->inkeys); + if (p->delme) + free(p); return -1; } } else { ast_log(LOG_NOTICE, "Host '%s' trying to do RSA authentication, but we have no inkeys\n", peer); + if (p->delme) + free(p); return -1; } } else if (strlen(secret) && strstr(p->methods, "plaintext")) { /* They've provided a plain text password and we support that */ if (strcmp(secret, p->secret)) { ast_log(LOG_NOTICE, "Host %s did not provide proper plaintext password for '%s'\n", inet_ntoa(sin->sin_addr), p->name); + if (p->delme) + free(p); return -1; } else iaxs[callno]->state |= IAX_STATE_AUTHENTICATED; - } else if (strlen(md5secret) && strstr(p->methods, "md5") && strlen(p->challenge)) { + } else if (strlen(md5secret) && strstr(p->methods, "md5") && strlen(iaxs[callno]->challenge)) { struct MD5Context md5; unsigned char digest[16]; MD5Init(&md5); - MD5Update(&md5, p->challenge, strlen(p->challenge)); + MD5Update(&md5, iaxs[callno]->challenge, strlen(iaxs[callno]->challenge)); MD5Update(&md5, p->secret, strlen(p->secret)); MD5Final(digest, &md5); for (x=0;x<16;x++) MYSNPRINTF "%2.2x", digest[x]); if (strcasecmp(requeststr, md5secret)) { ast_log(LOG_NOTICE, "Host %s failed MD5 authentication for '%s' (%s != %s)\n", inet_ntoa(sin->sin_addr), p->name, requeststr, md5secret); + if (p->delme) + free(p); return -1; } else iaxs[callno]->state |= IAX_STATE_AUTHENTICATED; } else if (strlen(md5secret) || strlen(secret)) { ast_log(LOG_NOTICE, "Inappropriate authentication received\n"); + if (p->delme) + free(p); return -1; } strncpy(iaxs[callno]->peer, peer, sizeof(iaxs[callno]->peer)-1); /* Choose lowest expirey number */ if (expire && (expire < iaxs[callno]->expirey)) iaxs[callno]->expirey = expire; + if (p->delme) + free(p); return 0; } @@ -3223,27 +3352,40 @@ static int update_registry(char *name, struct sockaddr_in *sin, int callno) struct iax_peer *p; for (p = peerl.peers;p;p = p->next) { if (!strcasecmp(name, p->name)) { - if (memcmp(&p->addr, sin, sizeof(p->addr))) { - if (iax_regfunk) - iax_regfunk(p->name, 1); - if (option_verbose > 2) + break; + } + } +#ifdef MYSQL_FRIENDS + if (!p) + p = mysql_peer(name); +#endif + if (p) { +#ifdef MYSQL_FRIENDS + if (p->delme) + mysql_update_peer(name, sin); +#endif + if (memcmp(&p->addr, sin, sizeof(p->addr))) { + if (iax_regfunk) + iax_regfunk(p->name, 1); + if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "Registered '%s' (%s) at %s:%d\n", p->name, iaxs[callno]->state & IAX_STATE_AUTHENTICATED ? "AUTHENTICATED" : "UNAUTHENTICATED", inet_ntoa(sin->sin_addr), htons(sin->sin_port)); - iax_poke_peer(p); - } - /* Update the host */ - memcpy(&p->addr, sin, sizeof(p->addr)); - /* Setup the expirey */ - if (p->expire > -1) - ast_sched_del(sched, p->expire); - p->expire = ast_sched_add(sched, p->expirey * 1000, expire_registry, (void *)p); - MYSNPRINTF "peer=%s;yourip=%s;yourport=%d;refresh=%d;", - p->name, inet_ntoa(p->addr.sin_addr), ntohs(p->addr.sin_port), p->expirey); - if (p->hascallerid) - MYSNPRINTF "callerid=%s;", p->callerid); - requeststr[strlen(requeststr)-1] = '\0'; - return send_command_final(iaxs[callno], AST_FRAME_IAX, AST_IAX_COMMAND_REGACK, 0, requeststr, strlen(requeststr) + 1, -1);; - } + iax_poke_peer(p); + } + /* Update the host */ + memcpy(&p->addr, sin, sizeof(p->addr)); + /* Setup the expirey */ + if (p->expire > -1) + ast_sched_del(sched, p->expire); + p->expire = ast_sched_add(sched, p->expirey * 1000, expire_registry, (void *)p); + MYSNPRINTF "peer=%s;yourip=%s;yourport=%d;refresh=%d;", + p->name, inet_ntoa(p->addr.sin_addr), ntohs(p->addr.sin_port), p->expirey); + if (p->hascallerid) + MYSNPRINTF "callerid=%s;", p->callerid); + requeststr[strlen(requeststr)-1] = '\0'; + if (p->delme) + free(p); + return send_command_final(iaxs[callno], AST_FRAME_IAX, AST_IAX_COMMAND_REGACK, 0, requeststr, strlen(requeststr) + 1, -1);; } ast_log(LOG_WARNING, "No such peer '%s'\n", name); return -1; @@ -3255,17 +3397,26 @@ static int registry_authrequest(char *name, int callno) struct iax_peer *p; for (p = peerl.peers;p;p = p->next) { if (!strcasecmp(name, p->name)) { - MYSNPRINTF "methods=%s;", p->methods); - if (strstr(p->methods, "md5") || strstr(p->methods, "rsa")) { - /* Build the challenge */ - snprintf(p->challenge, sizeof(p->challenge), "%d", rand()); - MYSNPRINTF "challenge=%s;", p->challenge); - } - MYSNPRINTF "peer=%s;", name); - requeststr[strlen(requeststr)-1] = '\0'; - return send_command(iaxs[callno], AST_FRAME_IAX, AST_IAX_COMMAND_REGAUTH, 0, requeststr, strlen(requeststr) + 1, -1);; + break; } } +#ifdef MYSQL_FRIENDS + if (!p) + p = mysql_peer(name); +#endif + if (p) { + MYSNPRINTF "methods=%s;", p->methods); + if (strstr(p->methods, "md5") || strstr(p->methods, "rsa")) { + /* Build the challenge */ + snprintf(iaxs[callno]->challenge, sizeof(iaxs[callno]->challenge), "%d", rand()); + MYSNPRINTF "challenge=%s;", iaxs[callno]->challenge); + } + MYSNPRINTF "peer=%s;", name); + requeststr[strlen(requeststr)-1] = '\0'; + if (p->delme) + free(p); + return send_command(iaxs[callno], AST_FRAME_IAX, AST_IAX_COMMAND_REGAUTH, 0, requeststr, strlen(requeststr) + 1, -1); + } ast_log(LOG_WARNING, "No such peer '%s'\n", name); return 0; } @@ -4662,6 +4813,17 @@ static int set_config(char *config_file, struct sockaddr_in* sin){ } else { amaflags = format; } + +#ifdef MYSQL_FRIENDS + } else if (!strcasecmp(v->name, "dbuser")) { + strncpy(mydbuser, v->value, sizeof(mydbuser) - 1); + } else if (!strcasecmp(v->name, "dbpass")) { + strncpy(mydbpass, v->value, sizeof(mydbpass) - 1); + } else if (!strcasecmp(v->name, "dbhost")) { + strncpy(mydbhost, v->value, sizeof(mydbhost) - 1); + } else if (!strcasecmp(v->name, "dbname")) { + strncpy(mydbname, v->value, sizeof(mydbname) - 1); +#endif } //else if (strcasecmp(v->name,"type")) // ast_log(LOG_WARNING, "Ignoring %s\n", v->name); v = v->next; @@ -4698,6 +4860,21 @@ static int set_config(char *config_file, struct sockaddr_in* sin){ cat = ast_category_browse(cfg, cat); } ast_destroy(cfg); +#ifdef MYSQL_FRIENDS + /* Connect to db if appropriate */ + if (strlen(mydbname)) { + mysql = mysql_init(NULL); + if (!mysql_real_connect(mysql, mydbhost[0] ? mydbhost : NULL, mydbuser, mydbpass, mydbname, 0, NULL, 0)) { + memset(mydbpass, '*', strlen(mydbpass)); + ast_log(LOG_WARNING, "Database connection failed (db=%s, host=%s, user=%s, pass=%s)!\n", + mydbname, mydbhost, mydbuser, mydbpass); + free(mysql); + mysql = NULL; + } else + ast_verbose(VERBOSE_PREFIX_1 "Connected to database '%s' on '%s' as '%s'\n", + mydbname, mydbhost, mydbuser); + } +#endif return capability; }