Index: chan_sip.c =================================================================== RCS file: /usr/cvsroot/asterisk/channels/chan_sip.c,v retrieving revision 1.305 diff -u -r1.305 chan_sip.c --- chan_sip.c 5 Mar 2004 18:09:35 -0000 1.305 +++ chan_sip.c 8 Mar 2004 06:09:33 -0000 @@ -75,6 +75,10 @@ #define SIP_DTMF_INBAND (1 << 1) #define SIP_DTMF_INFO (1 << 2) +#define SIP_TYPE_USER (1 << 0) +#define SIP_TYPE_PEER (1 << 1) +#define SIP_TYPE_FRIEND (SIP_TYPE_USER|SIP_TYPE_PEER) + static int max_expiry = DEFAULT_MAX_EXPIRY; static int default_expiry = DEFAULT_DEFAULT_EXPIRY; @@ -85,6 +89,11 @@ #define DEFAULT_RETRANS 1000 /* How frequently to retransmit */ #define MAX_RETRANS 5 /* Try only 5 times for retransmissions */ +// From acl.c... these should be moved to acl.h from here, and +// from acl.c, and then replaced with the appropriate #include (rgagnon) +#define AST_SENSE_DENY 0 +#define AST_SENSE_ALLOW 1 + #ifdef MYSQL_FRIENDS static ast_mutex_t mysqllock = AST_MUTEX_INITIALIZER; static MYSQL *mysql; @@ -294,7 +303,7 @@ /* Users who can access various contexts */ char name[80]; char secret[80]; - char md5secret[80]; + char md5secret[80]; char context[80]; char callerid[80]; char methods[80]; @@ -315,6 +324,7 @@ int outgoinglimit; int restrictcid; struct ast_ha *ha; + int temponly; struct sip_user *next; }; @@ -709,10 +719,76 @@ } } +static struct ast_ha *mysql_getacl(char *name, struct ast_ha *ha) +{ + char pattern[50] = ""; //only needs 42, but just being safe + char ipaddr[21] = ""; + char netmask[21] = ""; + int sense = 0; + + if (mysql && strlen(name) < 128) { + char query[512] = ""; + int numfields, x; + char *username = NULL; + MYSQL_RES *result; + MYSQL_FIELD *fields; + MYSQL_ROW rowval; + + if (name) { + username = alloca(strlen(name) * 2 + 1); + mysql_real_escape_string(mysql, username, name, strlen(name)); + } + snprintf(query, sizeof(query), "SELECT * FROM sipacl WHERE name=\"%s\";", + username); + ast_mutex_lock(&mysqllock); + mysql_query(mysql, query); + if ((result = mysql_store_result(mysql))) { + while ((rowval = mysql_fetch_row(result))) { + numfields = mysql_num_fields(result); + fields = mysql_fetch_fields(result); + for (x=0;xsin_addr), ntohs(sin->sin_port)); + snprintf(query, sizeof(query), + "SELECT * FROM sipfriends WHERE ipaddr=\"%s\" AND port=\"%d\"" + " AND (type=\"%d\" OR type=\"%d\");", + inet_ntoa(sin->sin_addr), ntohs(sin->sin_port), + SIP_TYPE_PEER, SIP_TYPE_FRIEND); else - snprintf(query, sizeof(query), "SELECT * FROM sipfriends WHERE name=\"%s\"", name); + snprintf(query, sizeof(query), + "SELECT * FROM sipfriends WHERE name=\"%s\"" + " AND (type=\"%d\" OR type=\"%d\");", + name, SIP_TYPE_PEER, SIP_TYPE_FRIEND); ast_mutex_lock(&mysqllock); mysql_query(mysql, query); if ((result = mysql_store_result(mysql))) { @@ -756,9 +839,18 @@ if (sscanf(rowval[x], "%i", &port) != 1) port = 0; p->addr.sin_port = htons(port); + } else if (!strcasecmp(fields[x].name, "nat")) { + if (sscanf(rowval[x], "%i", &nat) != 1) + nat = globalnat; + } else if (!strcasecmp(fields[x].name, "dtmfmode")) { + if (sscanf(rowval[x], "%i", &dtmfmode) != 1) + dtmfmode = globaldtmfmode; } else if (!strcasecmp(fields[x].name, "regseconds")) { if (sscanf(rowval[x], "%li", ®seconds) != 1) regseconds = 0; + } else if (!strcasecmp(fields[x].name, "codecflags")) { + if (sscanf(rowval[x], "%i", &codecflags) != 1) + codecflags = capability; } } } @@ -772,20 +864,177 @@ ast_mutex_unlock(&mysqllock); } if (!success) { - free(p); + if (p) free(p); p = NULL; } else { p->dynamic = 1; - p->capability = capability; - p->nat = globalnat; - p->dtmfmode = globaldtmfmode; + p->capability = codecflags; + if (p->capability == 0) { + ast_log(LOG_WARNING, "codecflags for peer: %s set to zero (none)\n", + peer); + } + p->nat = (nat ? -1 : 0); + + // Validate dtmfmode + switch (dtmfmode) { + case SIP_DTMF_RFC2833: + case SIP_DTMF_INBAND: + case SIP_DTMF_INFO: + break; + default: + dtmfmode = globaldtmfmode; + break; + } //end switch + p->dtmfmode = dtmfmode; + p->insecure = 1; p->expire = -1; p->temponly = 1; - + + //go get the acl if there is one + //Uses p->name here, and not "peer" because "peer" could be NULL + //on input to this function + p->ha = mysql_getacl(p->name, p->ha); } return p; } + +static struct sip_user *mysql_user(char *user) +{ + struct sip_user *u; + int success = 0; + int canreinvite = REINVITE_INVITE; + int nat = globalnat; + int dtmfmode = globaldtmfmode; + int codecflags = capability; + int restrictcid = 0; + int amaflags = 0; + char cidname[21] = ""; + char cidnumber[21] = ""; + + u = malloc(sizeof(struct sip_user)); + memset(u, 0, sizeof(struct sip_user)); + if (mysql && (!u || (strlen(user) < 128))) { + char query[512]; + char *name; + int numfields, x; + + MYSQL_RES *result; + MYSQL_FIELD *fields; + MYSQL_ROW rowval; + name = alloca(strlen(user) * 2 + 1); + mysql_real_escape_string(mysql, name, user, strlen(user)); + snprintf(query, sizeof(query), + "SELECT * FROM sipfriends WHERE name=\"%s\"" + " AND (type=\"%d\" OR type=\"%d\");", + name, SIP_TYPE_USER, SIP_TYPE_FRIEND); + 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(u->secret) - 1); + } else if (!strcasecmp(fields[x].name, "context")) { + strncpy(u->context, rowval[x], sizeof(u->context) - 1); + } else if (!strcasecmp(fields[x].name, "cidname")) { + strncpy(cidname, rowval[x], sizeof(cidname) - 1); + } else if (!strcasecmp(fields[x].name, "cidnumber")) { + strncpy(cidnumber, rowval[x], sizeof(cidnumber) - 1); + } else if (!strcasecmp(fields[x].name, "accountcode")) { + strncpy(u->accountcode, rowval[x], sizeof(u->accountcode) - 1); + } else if (!strcasecmp(fields[x].name, "nat")) { + if (sscanf(rowval[x], "%i", &nat) != 1) + nat = globalnat; + } else if (!strcasecmp(fields[x].name, "dtmfmode")) { + if (sscanf(rowval[x], "%i", &dtmfmode) != 1) + dtmfmode = globaldtmfmode; + } else if (!strcasecmp(fields[x].name, "canreinvite")) { + if (sscanf(rowval[x], "%i", &canreinvite) != 1) + canreinvite = 0; + } else if (!strcasecmp(fields[x].name, "restrictcid")) { + if (sscanf(rowval[x], "%i", &restrictcid) != 1) + restrictcid = 0; + } else if (!strcasecmp(fields[x].name, "amaflags")) { + if (sscanf(rowval[x], "%i", &amaflags) != 1) + amaflags = 0; + } else if (!strcasecmp(fields[x].name, "codecflags")) { + if (sscanf(rowval[x], "%i", &codecflags) != 1) + codecflags = capability; + } + } + } + } + mysql_free_result(result); + result = NULL; + } + ast_mutex_unlock(&mysqllock); + } + if (!success) { + if (u) free(u); + u = NULL; + } else { + strncpy(u->name, user, sizeof(u->name) - 1); + u->temponly = 1; + + // Validate codec flags... + u->capability = codecflags; + if (u->capability == 0) { + ast_log(LOG_WARNING, "codecflags for user: %s set to zero (none)\n", + user); + } + + // Validate dtmfmode + switch (dtmfmode) { + case SIP_DTMF_RFC2833: + case SIP_DTMF_INBAND: + case SIP_DTMF_INFO: + break; + default: + dtmfmode = globaldtmfmode; + break; + } //end switch + u->dtmfmode = dtmfmode; + + // Validate amaflags + switch (amaflags) { + case AST_CDR_OMIT: + case AST_CDR_BILLING: + case AST_CDR_DOCUMENTATION: + break; + default: + amaflags = 0; + break; + } //end switch + u->amaflags = amaflags; + + // double-check true/false fields from database + // DB uses 1/0 for true/false. Internally, we use -1/0 + u->canreinvite = (canreinvite ? -1 : 0); + u->nat = (nat ? -1 : 0); + u->restrictcid = (restrictcid ? -1 : 0); + + snprintf(u->callerid,sizeof(u->callerid),"\"%s\" <%s>", + cidname, cidnumber); + + // setup auth methods + if (!strlen(u->methods)) { + if (strlen(u->secret)) + strncpy(u->methods, "md5,plaintext", sizeof(u->methods) - 1); + else if (strlen(u->md5secret)) + strncpy(u->methods, "md5", sizeof(u->methods) - 1); + } + + //go get ACL if there is one + u->ha = mysql_getacl(user, u->ha); + } + return u; +} + #endif /* MYSQL_FRIENDS */ static int create_addr(struct sip_pvt *r, char *peer) @@ -861,8 +1110,10 @@ } memcpy(&r->recv, &r->sa, sizeof(r->recv)); } else { - if (p->temponly) + if (p->temponly) { + ast_free_ha(p->ha); free(p); + } p = NULL; } } @@ -902,8 +1153,11 @@ } else if (!p) return -1; else { - if (p->temponly) + if (p->temponly) { + ast_free_ha(p->ha); free(p); + p = NULL; + } return 0; } } @@ -3506,6 +3760,10 @@ if (!p->temponly) p->expire = ast_sched_add(sched, (expiry + 10) * 1000, expire_register, p); pvt->expiry = expiry; +#ifdef MYSQL_FRIENDS + //if (p->temponly) + // mysql_update_peer(p->name, &p->addr, p->username, expiry); +#endif snprintf(data, sizeof(data), "%s:%d:%d:%s", inet_ntoa(p->addr.sin_addr), ntohs(p->addr.sin_port), expiry, p->username); ast_db_put("SIP/Registry", p->name, data); if (inaddrcmp(&p->addr, &oldsin)) { @@ -3717,7 +3975,6 @@ md5_hash(resp_hash, resp); /* resp_hash now has the expected response, compare the two */ - if (response && !strncasecmp(response, resp_hash, strlen(resp_hash))) { /* Auth is OK */ res = 0; @@ -3787,6 +4044,14 @@ #ifdef MYSQL_FRIENDS if (!peer) peer = mysql_peer(name, NULL); + if (peer) { + // check if ACL allows this peer + if (ast_apply_ha(peer->ha, sin) == AST_SENSE_DENY) { + ast_free_ha(peer->ha); + free(peer); + peer = NULL; + } + } #endif if (peer) { if (!peer->dynamic) { @@ -3834,8 +4099,10 @@ } if (res < 0) transmit_response(p, "401 Unauthorized", &p->initreq); - if (peer && peer->temponly) + if (peer && peer->temponly) { + ast_free_ha(peer->ha); free(peer); + } return res; } @@ -4140,6 +4407,7 @@ } return 0; } + static char *get_calleridname(char *input,char *output) { char *end = strchr(input,'<'); @@ -4167,6 +4435,7 @@ } return output; } + static int check_user(struct sip_pvt *p, struct sip_request *req, char *cmd, char *uri, int reliable, struct sockaddr_in *sin) { struct sip_user *user; @@ -4215,46 +4484,63 @@ user = userl.users; while(user) { if (!strcasecmp(user->name, of) && ast_apply_ha(user->ha,sin)) { - p->nat = user->nat; - if (p->rtp) { - ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", p->nat); - ast_rtp_setnat(p->rtp, p->nat); - } - if (p->vrtp) { - ast_log(LOG_DEBUG, "Setting NAT on VRTP to %d\n", p->nat); - ast_rtp_setnat(p->vrtp, p->nat); - } - if (!(res = check_auth(p, req, p->randdata, sizeof(p->randdata), user->name, user->secret, user->md5secret, cmd, uri, reliable))) { - sip_cancel_destroy(p); - if (strlen(user->context)) - strncpy(p->context, user->context, sizeof(p->context) - 1); - if (strlen(user->callerid) && strlen(p->callerid)) - strncpy(p->callerid, user->callerid, sizeof(p->callerid) - 1); - strncpy(p->username, user->name, sizeof(p->username) - 1); - strncpy(p->peersecret, user->secret, sizeof(p->peersecret) - 1); - strncpy(p->peermd5secret, user->md5secret, sizeof(p->peermd5secret) - 1); - strncpy(p->accountcode, user->accountcode, sizeof(p->accountcode) -1); - strncpy(p->language, user->language, sizeof(p->language) -1); - p->canreinvite = user->canreinvite; - p->amaflags = user->amaflags; - p->callgroup = user->callgroup; - p->pickupgroup = user->pickupgroup; - p->restrictcid = user->restrictcid; - p->capability = user->capability; - p->jointcapability = user->capability; - if (user->dtmfmode) { - p->dtmfmode = user->dtmfmode; - if (p->dtmfmode & SIP_DTMF_RFC2833) - p->noncodeccapability |= AST_RTP_DTMF; - else - p->noncodeccapability &= ~AST_RTP_DTMF; - } - } break; } user = user->next; } +#ifdef MYSQL_FRIENDS + if (!user) { + user=mysql_user(of); + if (user) { + //check if user is denied in ACL + if (ast_apply_ha(user->ha, sin) == AST_SENSE_DENY) { + ast_free_ha(user->ha); + free(user); + user = NULL; + } + } + } +#endif + + if (user) { + p->nat = user->nat; + if (p->rtp) { + ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", p->nat); + ast_rtp_setnat(p->rtp, p->nat); + } + if (p->vrtp) { + ast_log(LOG_DEBUG, "Setting NAT on VRTP to %d\n", p->nat); + ast_rtp_setnat(p->vrtp, p->nat); + } + if (!(res = check_auth(p, req, p->randdata, sizeof(p->randdata), user->name, user->secret, user->md5secret, cmd, uri, reliable))) { + sip_cancel_destroy(p); + if (strlen(user->context)) + strncpy(p->context, user->context, sizeof(p->context) - 1); + if (strlen(user->callerid) && strlen(p->callerid)) + strncpy(p->callerid, user->callerid, sizeof(p->callerid) - 1); + strncpy(p->username, user->name, sizeof(p->username) - 1); + strncpy(p->peersecret, user->secret, sizeof(p->peersecret) - 1); + strncpy(p->peermd5secret, user->md5secret, sizeof(p->peermd5secret) - 1); + strncpy(p->accountcode, user->accountcode, sizeof(p->accountcode) -1); + strncpy(p->language, user->language, sizeof(p->language) -1); + p->canreinvite = user->canreinvite; + p->amaflags = user->amaflags; + p->callgroup = user->callgroup; + p->pickupgroup = user->pickupgroup; + p->restrictcid = user->restrictcid; + p->capability = user->capability; + p->jointcapability = user->capability; + if (user->dtmfmode) { + p->dtmfmode = user->dtmfmode; + if (p->dtmfmode & SIP_DTMF_RFC2833) + p->noncodeccapability |= AST_RTP_DTMF; + else + p->noncodeccapability &= ~AST_RTP_DTMF; + } + } + } ast_mutex_unlock(&userl.lock); + if (!user) { /* If we didn't find a user match, check for peers */ ast_mutex_lock(&peerl.lock); @@ -4271,40 +4557,66 @@ if (!peer) peer = mysql_peer(NULL, sin); #endif + /***************************************************************** + *** not in patch for now, as this could be another bug or not *** + //CHECK THE ACL!!!! if (peer) { - /* Take the peer */ - p->nat = peer->nat; - if (p->rtp) { - ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", p->nat); - ast_rtp_setnat(p->rtp, p->nat); - } - if (p->vrtp) { - ast_log(LOG_DEBUG, "Setting NAT on VRTP to %d\n", p->nat); - ast_rtp_setnat(p->vrtp, p->nat); - } - p->canreinvite = peer->canreinvite; - if (strlen(peer->username)) - strncpy(p->username, peer->username, sizeof(p->username) - 1); - strncpy(p->peername, peer->name, sizeof(p->peername) - 1); - if (strlen(peer->context)) - strncpy(p->context, peer->context, sizeof(p->context) - 1); - strncpy(p->peersecret, peer->secret, sizeof(p->peersecret) - 1); - strncpy(p->peermd5secret, peer->md5secret, sizeof(p->peermd5secret) - 1); - p->callgroup = peer->callgroup; - p->pickupgroup = peer->pickupgroup; - p->capability = peer->capability; - p->jointcapability = peer->capability; - if (peer->dtmfmode) { - p->dtmfmode = peer->dtmfmode; - if (p->dtmfmode & SIP_DTMF_RFC2833) - p->noncodeccapability |= AST_RTP_DTMF; - else - p->noncodeccapability &= ~AST_RTP_DTMF; + if (ast_apply_ha(peer->ha, sin) == AST_SENSE_DENY) { + //denied... if it was temponly, remove it from + //memory before NULLifying the pointer, but set the pointer + //to NULL either way + res = -1; //signify bad auth + if (peer->temponly) { + ast_free_ha(peer->ha); + free(peer); } - if (peer->temponly) + peer = NULL; + } + } + ****************************************************************/ + + if (peer) { + /* Take the peer */ + p->nat = peer->nat; + if (p->rtp) { + ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", p->nat); + ast_rtp_setnat(p->rtp, p->nat); + } + if (p->vrtp) { + ast_log(LOG_DEBUG, "Setting NAT on VRTP to %d\n", p->nat); + ast_rtp_setnat(p->vrtp, p->nat); + } + p->canreinvite = peer->canreinvite; + if (strlen(peer->username)) + strncpy(p->username, peer->username, sizeof(p->username) - 1); + strncpy(p->peername, peer->name, sizeof(p->peername) - 1); + if (strlen(peer->context)) + strncpy(p->context, peer->context, sizeof(p->context) - 1); + strncpy(p->peersecret, peer->secret, sizeof(p->peersecret) - 1); + strncpy(p->peermd5secret, peer->md5secret, sizeof(p->peermd5secret) - 1); + p->callgroup = peer->callgroup; + p->pickupgroup = peer->pickupgroup; + p->capability = peer->capability; + p->jointcapability = peer->capability; + if (peer->dtmfmode) { + p->dtmfmode = peer->dtmfmode; + if (p->dtmfmode & SIP_DTMF_RFC2833) + p->noncodeccapability |= AST_RTP_DTMF; + else + p->noncodeccapability &= ~AST_RTP_DTMF; + } + if (peer->temponly) { + ast_free_ha(peer->ha); free(peer); + peer = NULL; + } } } + if (user && user->temponly) { + ast_free_ha(user->ha); + free(user); + user=NULL; + } return res; }