/* * Remove used credentials from a SIP message header */ int consume_credentials(struct sip_msg* msg) { struct hdr_field* h; int len; /* skip requests that can't be authenticated */ if (msg->REQ_METHOD & (METHOD_ACK|METHOD_CANCEL|METHOD_PRACK)) return -1; get_authorized_cred(msg->authorization, &h); if (!h) { get_authorized_cred(msg->proxy_auth, &h); if (!h) { LOG(L_ERR, "auth:consume_credentials: No authorized " "credentials found (error in scripts)\n"); return -1; } } len = h->len; if (del_lump(msg, h->name.s - msg->buf, len, 0) == 0) { LOG(L_ERR, "auth:consume_credentials: Can't remove credentials\n"); return -1; } return 1; }
/* * Remove used credentials from a SIP message header */ int consume_credentials(struct sip_msg* _m, char* _s1, char* _s2) { struct hdr_field* h; int len; get_authorized_cred(_m->authorization, &h); if (!h) { get_authorized_cred(_m->proxy_auth, &h); if (!h) { if (_m->REQ_METHOD!=METHOD_ACK && _m->REQ_METHOD!=METHOD_CANCEL) { LM_ERR("no authorized credentials found (error in scripts)\n"); } return -1; } } len=h->len; if (del_lump(_m, h->name.s - _m->buf, len, 0) == 0) { LM_ERR("can't remove credentials\n"); return -1; } return 1; }
/* * Remove used credentials from a SIP message header */ int consume_credentials(struct sip_msg* msg, char* s1, char* s2) { struct hdr_field* h; int len; get_authorized_cred(msg->authorization, &h); if (!h) { get_authorized_cred(msg->proxy_auth, &h); if (!h) { if (msg->REQ_METHOD != METHOD_ACK && msg->REQ_METHOD != METHOD_CANCEL) { LOG(L_ERR, "auth:consume_credentials: No authorized " "credentials found (error in scripts)\n"); } return -1; } } len = h->len; if (del_lump(msg, h->name.s - msg->buf, len, 0) == 0) { LOG(L_ERR, "auth:consume_credentials: Can't remove credentials\n"); return -1; } return 1; }
/* * Create and send a challenge */ static inline int challenge(struct sip_msg* _msg, str* _realm, int _qop, int _code, char* _message, char* _challenge_msg) { int auth_hf_len; struct hdr_field* h; auth_body_t* cred = 0; char *auth_hf; int ret, hftype = 0; /* Makes gcc happy */ struct sip_uri uri; switch(_code) { case 401: get_authorized_cred(_msg->authorization, &h); hftype = HDR_AUTHORIZATION; break; case 407: get_authorized_cred(_msg->proxy_auth, &h); hftype = HDR_PROXYAUTH; break; } if (h) cred = (auth_body_t*)(h->parsed); if (_realm->len == 0) { if (get_realm(_msg, hftype, &uri) < 0) { LOG(L_ERR, "challenge(): Error while extracting URI\n"); if (send_resp(_msg, 400, MESSAGE_400, 0, 0) == -1) { LOG(L_ERR, "challenge(): Error while sending response\n"); return -1; } return 0; } _realm = &uri.host; strip_realm(_realm); } auth_hf = build_auth_hf(0, (cred ? cred->stale : 0), _realm, &auth_hf_len, _qop, _challenge_msg); if (!auth_hf) { LOG(L_ERR, "ERROR: challenge: no mem w/cred\n"); return -1; } ret = send_resp(_msg, _code, _message, auth_hf, auth_hf_len); if (auth_hf) pkg_free(auth_hf); if (ret == -1) { LOG(L_ERR, "challenge(): Error while sending response\n"); return -1; } return 0; }
/* Extract username attribute from authorized credentials */ static inline str* cred_user(struct sip_msg* rq) { 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 || !cred->digest.username.user.len) return 0; return &cred->digest.username.user; }
/* 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; }
static inline int get_cred(struct sip_msg *_m, str *_username) { struct hdr_field *h; get_authorized_cred(_m->authorization, &h); if (!h) { get_authorized_cred(_m->proxy_auth, &h); if (!h) { LM_ERR("No authorized credentials found\n"); return -1; } } *_username = ((auth_body_t *) h->parsed)->digest.username.whole; return 0; }
/* * Check if the username matches the username in credentials */ int is_user(struct sip_msg* _m, char* _user, char* _str2) { str s; struct hdr_field* h; auth_body_t* c; if (get_str_fparam(&s, _m, (fparam_t *)_user) < 0) { ERR("is_user: failed to recover parameter.\n"); return -1; } get_authorized_cred(_m->authorization, &h); if (!h) { get_authorized_cred(_m->proxy_auth, &h); if (!h) { LOG(L_ERR, "is_user(): No authorized credentials found (error in scripts)\n"); LOG(L_ERR, "is_user(): Call {www,proxy}_authorize before calling is_user function !\n"); return -1; } } c = (auth_body_t*)(h->parsed); if (!c->digest.username.user.len) { DBG("is_user(): Username not found in credentials\n"); return -1; } if (s.len != c->digest.username.user.len) { DBG("is_user(): Username length does not match\n"); return -1; } if (!memcmp(s.s, c->digest.username.user.s, s.len)) { DBG("is_user(): Username matches\n"); return 1; } else { DBG("is_user(): Username differs\n"); return -1; } }
/* * Check if the username matches the username in credentials */ int is_user(struct sip_msg* _m, char* _user, char* _str2) { str* s; struct hdr_field* h; auth_body_t* c; s = (str*)_user; 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"); LM_ERR("Call {www,proxy}_authorize before calling is_user function !\n"); return -1; } } c = (auth_body_t*)(h->parsed); if (!c->digest.username.user.len) { LM_DBG("username not found in credentials\n"); return -1; } if (s->len != c->digest.username.user.len) { LM_DBG("username length does not match\n"); return -1; } if (!memcmp(s->s, c->digest.username.user.s, s->len)) { LM_DBG("username matches\n"); return 1; } else { LM_DBG("username differs\n"); return -1; } }
static str get_diverter(struct sip_msg *msg) { struct hdr_field *header; dig_cred_t *credentials; int_str avpname, avpvalue; static str diverter; diverter.s = "None"; diverter.len = 4; avpname.n = diverter_avp_id; if (search_first_avp(AVP_VAL_STR, avpname, &avpvalue, NULL)) { // have a diverted call diverter = avpvalue.s; } else { get_authorized_cred(msg->proxy_auth, &header); if (header) { credentials = &((auth_body_t*)(header->parsed))->digest; } else { if (parse_headers(msg, HDR_PROXYAUTH_F, 0) == -1) { LOG(L_ERR, "cannot parse Proxy-Authorization header\n"); return diverter; } if (!msg->proxy_auth) return diverter; if (parse_credentials(msg->proxy_auth) != 0) { LOG(L_ERR, "cannot parse credentials\n"); return diverter; } credentials = &((auth_body_t*)(msg->proxy_auth->parsed))->digest; } if (credentials->username.user.len > 0 && credentials->username.domain.len > 0 && credentials->realm.len == 0 && credentials->nonce.len == 0 && credentials->response.len == 0) { // this is a call diverted from the failure route // and sent back to proxy with append_pa_hf() diverter = credentials->username.whole; } } return diverter; }
/* * 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; } }
/*! * \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; }
static int load_avp_user(struct sip_msg* msg, str* prefix, load_avp_param_t type) { static char rad_msg[4096]; str user_domain, buffer; str* user, *domain, *uri; struct hdr_field* h; dig_cred_t* cred = 0; int_str name, val; unsigned short flags; VALUE_PAIR* send, *received, *vp; UINT4 service; struct sip_uri puri; send = received = 0; user_domain.s = 0; switch(type) { case LOAD_CALLER: /* Use From header field */ if (parse_from_header(msg) < 0) { LOG(L_ERR, "ERROR:avp_radius:load_avp_user: Error while " "parsing From header field\n"); return -1; } uri = &get_from(msg)->uri; if (parse_uri(uri->s, uri->len, &puri) == -1) { LOG(L_ERR, "ERROR:avp_radius:load_avp_user: Error while " "parsing From URI\n"); return -1; } user = &puri.user; domain = &puri.host; service = vals[V_SIP_CALLER_AVPS].v; break; case LOAD_CALLEE: /* Use the Request-URI */ if (parse_sip_msg_uri(msg) < 0) { LOG(L_ERR, "ERROR:avp_radius:load_avp_user: Error while " "parsing Request-URI\n"); return -1; } if (msg->parsed_uri.user.len == 0) { LOG(L_ERR, "ERROR:avp_radius:load_avp_user: Request-URI user " "is missing\n"); return -1; } user = &msg->parsed_uri.user; domain = &msg->parsed_uri.host; service = vals[V_SIP_CALLEE_AVPS].v; break; case LOAD_DIGEST: /* Use digest credentials */ get_authorized_cred(msg->proxy_auth, &h); if (!h) { LOG(L_ERR, "ERROR:avp_radius:load_avp_user: No authoried " "credentials\n"); return -1; } cred = &((auth_body_t*)(h->parsed))->digest; user = &cred->username.user; domain = &cred->realm; service = vals[V_SIP_CALLER_AVPS].v; break; default: LOG(L_ERR, "ERROR:avp_radius:avp_load_user: Unknown user type\n"); return -1; } user_domain.len = user->len + 1 + domain->len; user_domain.s = (char*)pkg_malloc(user_domain.len); if (!user_domain.s) { LOG(L_ERR, "ERROR:avp_radius:avp_load_user: No pkg memory left\n"); return -1; } memcpy(user_domain.s, user->s, user->len); user_domain.s[user->len] = '@'; memcpy(user_domain.s + user->len + 1, domain->s, domain->len); if (!rc_avpair_add(rh, &send, attrs[A_USER_NAME].v, user_domain.s, user_domain.len, 0)) { LOG(L_ERR, "ERROR:avp_radius:avp_load_user: Error adding " "PW_USER_NAME\n"); goto error; } if (!rc_avpair_add(rh, &send, attrs[A_SERVICE_TYPE].v, &service, -1, 0)) { LOG(L_ERR, "ERROR:avp_radius:avp_load_user: Error adding " "PW_SERVICE_TYPE\n"); goto error; } if (rc_auth(rh, 0, send, &received, rad_msg) == OK_RC) { DBG("DEBUG:avp_radius:avp_load_user: rc_auth Success\n"); rc_avpair_free(send); pkg_free(user_domain.s); vp = received; for( ; (vp=rc_avpair_get(vp,attrs[A_SIP_AVP].v,0)) ; vp=vp->next) { flags = 0; if (extract_avp( vp, &flags, &name, &val)!=0 ) continue; /* append prefix only if AVP has name */ if (flags&AVP_NAME_STR) { buffer.len = prefix->len + name.s->len; buffer.s = (char*)pkg_malloc(buffer.len); if (!buffer.s) { LOG(L_ERR, "ERROR:avp_radius:avp_load_user: "******"No pkg memory left\n"); return -1; } memcpy(buffer.s, prefix->s, prefix->len); memcpy(buffer.s + prefix->len, name.s->s, name.s->len); name.s = &buffer; } else { buffer.s = 0; } if (add_avp( flags, name, val) < 0) { LOG(L_ERR, "ERROR:avp_radius:avp_load_user: Unable to create " "a new AVP\n"); } else { DBG("DEBUG:avp_radius:generate_avps: " "AVP '%.*s'/%d='%.*s'/%d has been added\n", (flags&AVP_NAME_STR)?name.s->len:4, (flags&AVP_NAME_STR)?name.s->s:"null", (flags&AVP_NAME_STR)?0:name.n, (flags&AVP_VAL_STR)?val.s->len:4, (flags&AVP_VAL_STR)?val.s->s:"null", (flags&AVP_VAL_STR)?0:val.n ); } if (buffer.s) pkg_free(buffer.s); } rc_avpair_free(received); return 1; } else { LOG(L_ERR,"ERROR:avp_radius:avp_load_user: rc_auth failed\n"); } error: if (send) rc_avpair_free(send); if (received) rc_avpair_free(received); if (user_domain.s) pkg_free(user_domain.s); return -1; }
/* * 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; } }
/* * Create and send a challenge */ static inline int challenge(struct sip_msg* _msg, gparam_p _realm, int _qop, int _code, char* _message, char* _challenge_msg) { int auth_hf_len; struct hdr_field* h; auth_body_t* cred = 0; char *auth_hf; int ret; hdr_types_t hftype = 0; /* Makes gcc happy */ struct sip_uri *uri; str realm; str reason; switch(_code) { case 401: get_authorized_cred(_msg->authorization, &h); hftype = HDR_AUTHORIZATION_T; break; case 407: get_authorized_cred(_msg->proxy_auth, &h); hftype = HDR_PROXYAUTH_T; break; } if (h) cred = (auth_body_t*)(h->parsed); if(fixup_get_svalue(_msg, _realm, &realm)!=0) { LM_ERR("invalid realm parameter"); if (send_resp(_msg, 500, &auth_500_err, 0, 0)==-1) return -1; else return 0; } if (realm.len == 0) { if (get_realm(_msg, hftype, &uri) < 0) { LM_ERR("failed to extract URI\n"); if (send_resp(_msg, 400, &auth_400_err, 0, 0) == -1) { LM_ERR("failed to send the response\n"); return -1; } return 0; } realm = uri->host; strip_realm(&realm); } auth_hf = build_auth_hf(0, (cred ? cred->stale : 0), &realm, &auth_hf_len, _qop, _challenge_msg); if (!auth_hf) { LM_ERR("failed to generate nonce\n"); return -1; } reason.s = _message; reason.len = strlen(_message); ret = send_resp(_msg, _code, &reason, auth_hf, auth_hf_len); if (auth_hf) pkg_free(auth_hf); if (ret == -1) { LM_ERR("failed to send the response\n"); return -1; } 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 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 if a header field contains the same username * as digest credentials */ static inline int check_username(struct sip_msg* _m, str* _uri) { struct hdr_field* h; auth_body_t* c; struct sip_uri puri; db_key_t keys[3]; db_val_t vals[3]; db_key_t cols[1]; db_res_t* res; if (!_uri) { LOG(L_ERR, "check_username(): Bad parameter\n"); return -1; } /* Get authorized digest credentials */ get_authorized_cred(_m->authorization, &h); if (!h) { get_authorized_cred(_m->proxy_auth, &h); if (!h) { LOG(L_ERR, "check_username(): No authorized credentials found (error in scripts)\n"); LOG(L_ERR, "check_username(): Call {www,proxy}_authorize before calling check_* function !\n"); return -2; } } c = (auth_body_t*)(h->parsed); /* Parse To/From URI */ if (parse_uri(_uri->s, _uri->len, &puri) < 0) { LOG(L_ERR, "check_username(): Error while parsing URI\n"); return -3; } /* Make sure that the URI contains username */ if (!puri.user.len) { LOG(L_ERR, "check_username(): Username not found in URI\n"); return -4; } /* 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) { /* Make sure that From/To URI domain and digest realm are equal * FIXME: Should we move this outside this condition and make it general ? */ if (puri.host.len != c->digest.realm.len) { LOG(L_ERR, "check_username(): Digest realm and URI domain do not match\n"); return -5; } if (strncasecmp(puri.host.s, c->digest.realm.s, puri.host.len) != 0) { DBG("check_username(): Digest realm and URI domain do not match\n"); return -6; } if (db_use_table(db_handle, uri_table) < 0) { LOG(L_ERR, "check_username(): Error while trying to use uri table\n"); } keys[0] = uri_user_col; keys[1] = uri_domain_col; keys[2] = uri_uriuser_col; cols[0] = uri_user_col; 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) = c->digest.realm; VAL_STR(vals + 2) = puri.user; if (db_query(db_handle, keys, 0, vals, cols, 3, 1, 0, &res) < 0) { LOG(L_ERR, "check_username(): Error while querying database\n"); return -7; } /* 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) { DBG("check_username(): From/To user '%.*s' is spoofed\n", puri.user.len, ZSW(puri.user.s)); db_free_query(db_handle, res); return -8; } else { DBG("check_username(): From/To user '%.*s' and auth user match\n", puri.user.len, ZSW(puri.user.s)); db_free_query(db_handle, res); return 1; } } else { /* URI table not used, simply compare digest username and From/To * username, the comparison is case insensitive */ if (puri.user.len == c->digest.username.user.len) { if (!strncasecmp(puri.user.s, c->digest.username.user.s, puri.user.len)) { DBG("check_username(): Digest username and URI username match\n"); return 1; } } DBG("check_username(): Digest username and URI username do NOT match\n"); return -9; } }
/* it checks if a user is member of a group */ int diameter_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; struct hdr_field* h; struct sip_uri puri; AAAMessage *req; AAA_AVP *avp; int ret; unsigned int tmp; grp = (str*)_group; /* via fixup */ hf_type = (int)(long)_hf; uri.s = 0; uri.len = 0; /* extract the uri according with the _hf parameter */ switch(hf_type) { case 1: /* Request-URI */ uri = *(GET_RURI(_m)); break; case 2: /* To */ if (get_to_uri(_m, &uri) < 0) { LM_ERR("failed to extract To\n"); return -2; } break; case 3: /* From */ if (get_from_uri(_m, &uri) < 0) { LM_ERR("failed to extract From URI\n"); return -3; } 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) { if (parse_uri(uri.s, uri.len, &puri) < 0) { LM_ERR("failed to parse URI\n"); return -5; } user = puri.user; domain = puri.host; } else { user = cred->username.user; domain = cred->realm; } /* user@domain mode */ if (use_domain) { user_name.s = 0; user_name.len = user.len + domain.len; if(user_name.len>0) { user_name.len++; 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); if(user.len>0) { user_name.s[user.len] = '@'; memcpy(user_name.s + user.len + 1, domain.s, domain.len); } else memcpy(user_name.s, domain.s, domain.len); } } else user_name = user; if ( (req=AAAInMessage(AA_REQUEST, AAA_APP_NASREQ))==NULL) { LM_ERR("can't create new AAA message!\n"); return -1; } /* Username AVP */ if( (avp=AAACreateAVP(AVP_User_Name, 0, 0, user_name.s, user_name.len, AVP_DUPLICATE_DATA)) == 0) { LM_ERR("no more pkg memory!\n"); goto error; } if( AAAAddAVPToMessage(req, avp, 0)!= AAA_ERR_SUCCESS) { LM_ERR("avp not added \n"); goto error1; } /* Usergroup AVP */ if( (avp=AAACreateAVP(AVP_User_Group, 0, 0, grp->s, grp->len, AVP_DUPLICATE_DATA)) == 0) { LM_ERR("no more pkg memory!\n"); goto error; } if( AAAAddAVPToMessage(req, avp, 0)!= AAA_ERR_SUCCESS) { LM_ERR("avp not added \n"); goto error1; } /* SIP_MSGID AVP */ LM_DBG("******* m_id=%d\n", _m->id); tmp = _m->id; if( (avp=AAACreateAVP(AVP_SIP_MSGID, 0, 0, (char*)(&tmp), sizeof(tmp), AVP_DUPLICATE_DATA)) == 0) { LM_ERR("no more pkg memory!\n"); goto error; } if( AAAAddAVPToMessage(req, avp, 0)!= AAA_ERR_SUCCESS) { LM_ERR("avp not added \n"); goto error1; } /* ServiceType AVP */ if( (avp=AAACreateAVP(AVP_Service_Type, 0, 0, SIP_GROUP_CHECK, SERVICE_LEN, AVP_DUPLICATE_DATA)) == 0) { LM_ERR("no more pkg memory!\n"); goto error; } if( AAAAddAVPToMessage(req, avp, 0)!= AAA_ERR_SUCCESS) { LM_ERR("avp not added \n"); goto error1; } /* Destination-Realm AVP */ uri = *(GET_RURI(_m)); parse_uri(uri.s, uri.len, &puri); if( (avp=AAACreateAVP(AVP_Destination_Realm, 0, 0, puri.host.s, puri.host.len, AVP_DUPLICATE_DATA)) == 0) { LM_ERR("no more pkg memory!\n"); goto error; } if( AAAAddAVPToMessage(req, avp, 0)!= AAA_ERR_SUCCESS) { LM_ERR("avp not added \n"); goto error1; } #ifdef DEBUG AAAPrintMessage(req); #endif /* build a AAA message buffer */ if(AAABuildMsgBuffer(req) != AAA_ERR_SUCCESS) { LM_ERR("message buffer not created\n"); goto error; } if(sockfd==AAA_NO_CONNECTION) { sockfd = init_mytcp(diameter_client_host, diameter_client_port); if(sockfd==AAA_NO_CONNECTION) { LM_ERR("failed to reconnect to Diameter client\n"); goto error; } } ret =tcp_send_recv(sockfd, req->buf.s, req->buf.len, rb, _m->id); if(ret == AAA_CONN_CLOSED) { LM_NOTICE("connection to Diameter client closed." "It will be reopened by the next request\n"); close(sockfd); sockfd = AAA_NO_CONNECTION; goto error; } if(ret != AAA_USER_IN_GROUP) { LM_ERR("message sending to the DIAMETER backend authorization server" "failed or user is not in group\n"); goto error; } AAAFreeMessage(&req); return 1; error1: AAAFreeAVP(&avp); error: AAAFreeMessage(&req); return -1; }