/* Extract realm attribute from authorized credentials */ static inline str* cred_realm(struct sip_msg* rq) { str* realm; struct hdr_field* h; auth_body_t* cred; get_authorized_cred(rq->proxy_auth, &h); if (!h) get_authorized_cred(rq->authorization, &h); if (!h) return 0; cred = (auth_body_t*)(h->parsed); if (!cred) return 0; realm = GET_REALM(&cred->digest); if (!realm->len || !realm->s) { return 0; } return realm; }
/*! * \brief Extract the username and domain from the SIP message * * Set the username and domain depending on the value of the SIP * message and the group check structure. * \param msg SIP message * \param gcp group check structure * \param username stored username * \param domain stored domain * \return 0 on success, -1 on failure */ int get_username_domain(struct sip_msg *msg, group_check_p gcp, str *username, str *domain) { struct sip_uri puri; struct sip_uri *turi; struct hdr_field* h; struct auth_body* c = 0; pv_value_t value; turi = NULL; switch(gcp->id) { case 1: /* Request-URI */ if(parse_sip_msg_uri(msg)<0) { LM_ERR("failed to get Request-URI\n"); return -1; } turi = &msg->parsed_uri; break; case 2: /* To */ if((turi=parse_to_uri(msg))==NULL) { LM_ERR("failed to get To URI\n"); return -1; } break; case 3: /* From */ if((turi=parse_from_uri(msg))==NULL) { LM_ERR("failed to get From URI\n"); return -1; } break; case 4: /* Credentials */ get_authorized_cred( msg->authorization, &h); if (!h) { get_authorized_cred( msg->proxy_auth, &h); if (!h) { LM_ERR("no authorized credentials found " "(error in scripts)\n"); return -1; } } c = (auth_body_t*)(h->parsed); break; case 5: /* AVP spec */ if(pv_get_spec_value( msg, &gcp->sp, &value)!=0 || value.flags&PV_VAL_NULL || value.rs.len<=0) { LM_ERR("no AVP found (error in scripts)\n"); return -1; } if (parse_uri(value.rs.s, value.rs.len, &puri) < 0) { LM_ERR("failed to parse URI <%.*s>\n",value.rs.len, value.rs.s); return -1; } turi = &puri; break; default: { LM_ERR("incorrect check id %d\n", gcp->id); return -1; } } if (gcp->id != 4) { *username = turi->user; *domain = turi->host; } else { *username = c->digest.username.user; *domain = *(GET_REALM(&c->digest)); } return 0; }
int get_username_domain(struct sip_msg *msg, str *hf_s, str *username, str *domain) { struct sip_uri puri; struct sip_uri *turi; struct hdr_field* h; struct auth_body* c = 0; /* Makes gcc happy */ turi = NULL; switch( hf_type(hf_s) ) { case 1: /* Request-URI */ if(parse_sip_msg_uri(msg)<0) { LM_ERR("failed to get Request-URI\n"); return -1; } turi = &msg->parsed_uri; break; case 2: /* To */ if((turi=parse_to_uri(msg))==NULL) { LM_ERR("failed to get To URI\n"); return -1; } break; case 3: /* From */ if((turi=parse_from_uri(msg))==NULL) { LM_ERR("failed to get From URI\n"); return -1; } break; case 4: /* Credentials */ get_authorized_cred( msg->authorization, &h); if (!h) { get_authorized_cred( msg->proxy_auth, &h); if (!h) { LM_ERR("no authorized credentials found " "(error in scripts)\n"); return -1; } } c = (auth_body_t*)(h->parsed); break; default: /* string */ if (parse_uri(hf_s->s, hf_s->len, &puri) < 0) { LM_ERR("failed to parse URI <%.*s>\n",hf_s->len, hf_s->s); return -1; } turi = &puri; break; } if ( c==NULL ) { *username = turi->user; *domain = turi->host; } else { *username = c->digest.username.user; *domain = *(GET_REALM(&c->digest)); } return 0; }
/* * Check from AAA server if a user belongs to a group. User-Name is digest * username or digest username@realm, SIP-Group is group, and Service-Type * is Group-Check. SIP-Group is SER specific attribute and Group-Check is * SER specific service type value. */ int aaa_is_user_in(struct sip_msg* _m, char* _hf, char* _group) { str *grp, user_name, user, domain; dig_cred_t* cred = 0; int hf_type; uint32_t service; aaa_message *send = NULL, *received = NULL; struct hdr_field* h; struct sip_uri *turi; grp = (str*)_group; /* via fixup */ hf_type = (int)(long)_hf; turi = 0; switch(hf_type) { case 1: /* Request-URI */ if(parse_sip_msg_uri(_m)<0) { LM_ERR("failed to get Request-URI\n"); return -1; } turi = &_m->parsed_uri; break; case 2: /* To */ if((turi=parse_to_uri(_m))==NULL) { LM_ERR("failed to get To URI\n"); return -1; } break; case 3: /* From */ if((turi=parse_from_uri(_m))==NULL) { LM_ERR("failed to get From URI\n"); return -1; } break; case 4: /* Credentials */ get_authorized_cred(_m->authorization, &h); if (!h) { get_authorized_cred(_m->proxy_auth, &h); if (!h) { LM_ERR("no authorized" " credentials found (error in scripts)\n"); return -4; } } cred = &((auth_body_t*)(h->parsed))->digest; break; } if (hf_type != 4) { user = turi->user; domain = turi->host; } else { user = cred->username.user; domain = *GET_REALM(cred); } if (user.s == NULL || user.len == 0) { LM_DBG("no username part\n"); return -1; } if (use_domain) { user_name.len = user.len + domain.len + 1; user_name.s = (char*)pkg_malloc(user_name.len); if (!user_name.s) { LM_ERR("no pkg memory left\n"); return -6; } memcpy(user_name.s, user.s, user.len); user_name.s[user.len] = '@'; memcpy(user_name.s + user.len + 1, domain.s, domain.len); } else { user_name = user; } if ((send = proto.create_aaa_message(conn, AAA_AUTH)) == NULL) { LM_ERR("failed to create new aaa message for auth \n"); return -1; } if (proto.avp_add(conn, send, &attrs[A_USER_NAME], user_name.s, user_name.len, 0)) { proto.destroy_aaa_message(conn, send); if (use_domain) pkg_free(user_name.s); return -7; } if (use_domain) pkg_free(user_name.s); if (proto.avp_add(conn, send, &attrs[A_SIP_GROUP], grp->s, grp->len, 0)) { proto.destroy_aaa_message(conn, send); LM_ERR("failed to add Sip-Group attribute\n"); return -8; } service = vals[V_GROUP_CHECK].value; if (proto.avp_add(conn, send, &attrs[A_SERVICE_TYPE], &service, -1, 0)) { proto.destroy_aaa_message(conn, send); LM_ERR("failed to add Service-Type attribute\n"); return -8; } /* Add CALL-ID in Acct-Session-Id Attribute */ if ((parse_headers(_m, HDR_CALLID_F, 0) == -1 || _m->callid == NULL) && _m->callid == NULL) { proto.destroy_aaa_message(conn, send); LM_ERR("msg parsing failed or callid not present"); return -10; } if (proto.avp_add(conn, send, &attrs[A_ACCT_SESSION_ID], _m->callid->body.s, _m->callid->body.len, 0)) { proto.destroy_aaa_message(conn, send); LM_ERR("unable to add CALL-ID attribute\n"); return -11; } if (!proto.send_aaa_request(conn, send, &received)) { LM_DBG("Success\n"); proto.destroy_aaa_message(conn, send); proto.destroy_aaa_message(conn, received); return 1; } else { LM_DBG("Failure\n"); proto.destroy_aaa_message(conn, send); proto.destroy_aaa_message(conn, received); return -12; } }
/* * Check if username in specified header field is in a table */ int is_user_in(struct sip_msg* _msg, char* _hf, char* _grp) { db_key_t keys[3]; db_val_t vals[3]; db_key_t col[1]; db_res_t* res; str uri; long hf_type; struct sip_uri puri; struct hdr_field* h; struct auth_body* c = 0; /* Makes gcc happy */ group_check_p gcp=NULL; xl_value_t value; keys[0] = user_column.s; keys[1] = group_column.s; keys[2] = domain_column.s; col[0] = group_column.s; gcp = (group_check_p)_hf; hf_type = (long)gcp->id; uri.s = 0; uri.len = 0; switch(hf_type) { case 1: /* Request-URI */ if (get_request_uri(_msg, &uri) < 0) { LOG(L_ERR, "is_user_in(): Error while obtaining username from Request-URI\n"); return -1; } break; case 2: /* To */ if (get_to_uri(_msg, &uri) < 0) { LOG(L_ERR, "is_user_in(): Error while extracting To username\n"); return -2; } break; case 3: /* From */ if (get_from_uri(_msg, &uri) < 0) { LOG(L_ERR, "is_user_in(): Error while extracting From username\n"); return -3; } break; case 4: /* Credentials */ get_authorized_cred(_msg->authorization, &h); if (!h) { get_authorized_cred(_msg->proxy_auth, &h); if (!h) { LOG(L_ERR, "is_user_in(): No authorized credentials found (error in scripts)\n"); return -1; } } c = (auth_body_t*)(h->parsed); break; case 5: /* AVP spec */ if(xl_get_spec_value(_msg, &gcp->sp, &value)!=0 || value.flags&XL_VAL_NULL || value.rs.len<=0) { LOG(L_ERR, "is_user_in(): no AVP found (error in scripts)\n"); return -1; } uri.s = value.rs.s; uri.len = value.rs.len; break; } if (hf_type != 4) { if (parse_uri(uri.s, uri.len, &puri) < 0) { LOG(L_ERR, "is_user_in(): Error while parsing URI\n"); return -5; } VAL_STR(vals) = puri.user; VAL_STR(vals + 2) = puri.host; } else { VAL_STR(vals) = c->digest.username.user; VAL_STR(vals + 2) = *(GET_REALM(&c->digest)); } VAL_TYPE(vals) = VAL_TYPE(vals + 1) = VAL_TYPE(vals + 2) = DB_STR; VAL_NULL(vals) = VAL_NULL(vals + 1) = VAL_NULL(vals + 2) = 0; VAL_STR(vals + 1) = *((str*)_grp); if (group_dbf.use_table(db_handle, table.s) < 0) { LOG(L_ERR, "is_user_in(): Error in use_table\n"); return -5; } if (group_dbf.query(db_handle, keys, 0, vals, col, (use_domain) ? (3): (2), 1, 0, &res) < 0) { LOG(L_ERR, "is_user_in(): Error while querying database\n"); return -5; } if (RES_ROW_N(res) == 0) { DBG("is_user_in(): User is not in group '%.*s'\n", ((str*)_grp)->len, ZSW(((str*)_grp)->s)); group_dbf.free_result(db_handle, res); return -6; } else { DBG("is_user_in(): User is in group '%.*s'\n", ((str*)_grp)->len, ZSW(((str*)_grp)->s)); group_dbf.free_result(db_handle, res); return 1; } }
/* * Check if a header field contains the same username * as digest credentials */ static inline int check_username(struct sip_msg* _m, struct sip_uri *_uri) { static db_ps_t my_ps = NULL; struct hdr_field* h; auth_body_t* c; db_key_t keys[3]; db_val_t vals[3]; db_key_t cols[1]; db_res_t* res = NULL; if (_uri == NULL) { LM_ERR("Bad parameter\n"); return ERR_INTERNAL; } /* Get authorized digest credentials */ get_authorized_cred(_m->authorization, &h); if (h == NULL) { get_authorized_cred(_m->proxy_auth, &h); if (h == NULL) { LM_ERR("No authorized credentials found (error in scripts)\n"); LM_ERR("Call {www,proxy}_authorize before calling check_* functions!\n"); update_stat(negative_checks, 1); return ERR_CREDENTIALS; } } c = (auth_body_t*)(h->parsed); /* Parse To/From URI */ /* Make sure that the URI contains username */ if (_uri->user.len == 0) { LM_ERR("Username not found in URI\n"); return ERR_USERNOTFOUND; } /* If use_uri_table is set, use URI table to determine if Digest username * and To/From username match. URI table is a table enumerating all allowed * usernames for a single, thus a user can have several different usernames * (which are different from digest username and it will still match) */ if (use_uri_table != 0) { keys[0] = &uridb_user_col; keys[1] = &uridb_domain_col; keys[2] = &uridb_uriuser_col; cols[0] = &uridb_user_col; /* The whole fields are type DB_STR, and not null */ VAL_TYPE(vals) = VAL_TYPE(vals + 1) = VAL_TYPE(vals + 2) = DB_STR; VAL_NULL(vals) = VAL_NULL(vals + 1) = VAL_NULL(vals + 2) = 0; VAL_STR(vals) = c->digest.username.user; VAL_STR(vals + 1) = *GET_REALM(&c->digest); VAL_STR(vals + 2) = _uri->user; uridb_dbf.use_table(db_handle, &db_table); CON_PS_REFERENCE(db_handle) = &my_ps; if (uridb_dbf.query(db_handle, keys, 0, vals, cols, 3, 1, 0, &res) < 0) { LM_ERR("Error while querying database\n"); return ERR_DBQUERY; } /* If the previous function returns at least one row, it means * there is an entry for given digest username and URI username * and thus this combination is allowed and the function will match */ if (RES_ROW_N(res) == 0) { LM_DBG("From/To user '%.*s' is spoofed\n", _uri->user.len, ZSW(_uri->user.s)); uridb_dbf.free_result(db_handle, res); update_stat(negative_checks, 1); return ERR_SPOOFEDUSER; } else { LM_DBG("From/To user '%.*s' and auth user match\n", _uri->user.len, ZSW(_uri->user.s)); uridb_dbf.free_result(db_handle, res); update_stat(positive_checks, 1); return OK; } } else { /* URI table not used, simply compare digest username and From/To * username, the comparison is case insensitive */ if (_uri->user.len == c->digest.username.user.len) { if (!strncasecmp(_uri->user.s, c->digest.username.user.s, _uri->user.len)) { LM_DBG("Digest username and URI username match\n"); update_stat(positive_checks, 1); return OK; } } LM_DBG("Digest username and URI username do NOT match\n"); update_stat(negative_checks, 1); return ERR_NOMATCH; } }
/* * Check from Radius if a user belongs to a group. User-Name is digest * username or digest username@realm, SIP-Group is group, and Service-Type * is Group-Check. SIP-Group is SER specific attribute and Group-Check is * SER specific service type value. */ int radius_is_user_in(struct sip_msg* _m, char* _hf, char* _group) { str *grp, user_name, user, domain, uri; dig_cred_t* cred = 0; int hf_type; UINT4 service; VALUE_PAIR *send, *received; static char msg[4096]; struct hdr_field* h; struct sip_uri puri; grp = (str*)_group; /* via fixup */ send = received = 0; hf_type = (int)(long)_hf; uri.s = 0; uri.len = 0; switch(hf_type) { case 1: /* Request-URI */ if (get_request_uri(_m, &uri) < 0) { LOG(L_ERR, "radius_is_user_in(): Error while extracting Request-URI\n"); return -1; } break; case 2: /* To */ if (get_to_uri(_m, &uri) < 0) { LOG(L_ERR, "radius_is_user_in(): Error while extracting To\n"); return -2; } break; case 3: /* From */ if (get_from_uri(_m, &uri) < 0) { LOG(L_ERR, "radius_is_user_in(): Error while extracting From\n"); return -3; } break; case 4: /* Credentials */ get_authorized_cred(_m->authorization, &h); if (!h) { get_authorized_cred(_m->proxy_auth, &h); if (!h) { LOG(L_ERR, "radius_is_user_in(): No authorized credentials found (error in scripts)\n"); return -4; } } cred = &((auth_body_t*)(h->parsed))->digest; break; } if (hf_type != 4) { if (parse_uri(uri.s, uri.len, &puri) < 0) { LOG(L_ERR, "radius_is_user_in(): Error while parsing URI\n"); return -5; } user = puri.user; domain = puri.host; } else { user = cred->username.user; domain = *GET_REALM(cred); } if (use_domain) { user_name.len = user.len + domain.len + 1; user_name.s = (char*)pkg_malloc(user_name.len); if (!user_name.s) { LOG(L_ERR, "radius_is_user_in(): No memory left\n"); return -6; } memcpy(user_name.s, user.s, user.len); user_name.s[user.len] = '@'; memcpy(user_name.s + user.len + 1, domain.s, domain.len); } else { user_name = user; } if (!rc_avpair_add(rh, &send, attrs[A_USER_NAME].v, user_name.s, user_name.len, 0)) { LOG(L_ERR, "radius_is_user_in(): Error adding User-Name attribute\n"); rc_avpair_free(send); if (use_domain) pkg_free(user_name.s); return -7; } if (use_domain) pkg_free(user_name.s); if (!rc_avpair_add(rh, &send, attrs[A_SIP_GROUP].v, grp->s, grp->len, 0)) { LOG(L_ERR, "radius_is_user_in(): Error adding Sip-Group attribute\n"); return -8; } service = vals[V_GROUP_CHECK].v; if (!rc_avpair_add(rh, &send, attrs[A_SERVICE_TYPE].v, &service, -1, 0)) { LOG(L_ERR, "radius_is_user_in(): Error adding Service-Type attribute\n"); rc_avpair_free(send); return -9; } if (rc_auth(rh, 0, send, &received, msg) == OK_RC) { DBG("radius_is_user_in(): Success\n"); rc_avpair_free(send); rc_avpair_free(received); return 1; } else { DBG("radius_is_user_in(): Failure\n"); rc_avpair_free(send); rc_avpair_free(received); return -11; } }