/* * Check from Radius if request URI belongs to a local user. * User-Name is user@host of request Uri and Service-Type is Call-Check. */ int radius_does_uri_exist(struct sip_msg* _m, char* _s1, char* _s2) { static char msg[4096]; VALUE_PAIR *send, *received; UINT4 service; char* at, *uri; send = received = 0; if (parse_sip_msg_uri(_m) < 0) { LM_ERR("parsing URI failed\n"); return -1; } uri = (char*)pkg_malloc(_m->parsed_uri.user.len + _m->parsed_uri.host.len + 2); if (!uri) { LM_ERR("no more pkg memory\n"); return -2; } at = uri; memcpy(at, _m->parsed_uri.user.s, _m->parsed_uri.user.len); at += _m->parsed_uri.user.len; *at = '@'; at++; memcpy(at , _m->parsed_uri.host.s, _m->parsed_uri.host.len); at += _m->parsed_uri.host.len; *at = '\0'; if (!rc_avpair_add(rh, &send, attrs[A_USER_NAME].v, uri, -1, 0)) { LM_ERR("adding User-Name failed\n"); rc_avpair_free(send); pkg_free(uri); return -3; } service = vals[V_CALL_CHECK].v; if (!rc_avpair_add(rh, &send, attrs[A_SERVICE_TYPE].v, &service, -1, 0)) { LM_ERR("adding service type failed\n"); rc_avpair_free(send); pkg_free(uri); return -4; } if (rc_auth(rh, 0, send, &received, msg) == OK_RC) { LM_DBG("success\n"); rc_avpair_free(send); generate_avps(received); rc_avpair_free(received); pkg_free(uri); return 1; } else { LM_DBG("failure\n"); rc_avpair_free(send); rc_avpair_free(received); pkg_free(uri); return -5; } }
static int load_user_attrs(struct sip_msg* msg, unsigned long flags, fparam_t* fp) { static char rad_msg[4096]; str uid; UINT4 service; VALUE_PAIR* send, *received; send = NULL; received = NULL; if (get_str_fparam(&uid, msg, (fparam_t*)fp) < 0) { ERR("Unable to get UID\n"); return -1; } service = vals[V_GET_USER_ATTRS].v; if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_USER_NAME].v), uid.s, uid.len, VENDOR(attrs[A_USER_NAME].v))) { ERR("Error while adding A_USER_NAME\n"); goto error; } if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_SER_SERVICE_TYPE].v), &vals[V_GET_USER_ATTRS].v, -1, VENDOR(attrs[A_SER_SERVICE_TYPE].v))) { ERR("Error adding A_SERVICE_TYPE\n"); goto error; } if (rc_auth(rh, 0, send, &received, rad_msg) != OK_RC) { DBG("load_user_attrs: Failure\n"); goto error; } DBG("load_user_attrs: Success\n"); rc_avpair_free(send); if (generate_avps(flags, received) < 0) { rc_avpair_free(received); goto error; } rc_avpair_free(received); return 1; error: if (send) rc_avpair_free(send); if (received) rc_avpair_free(send); return -1; }
/* * Check from Radius if URI user given as argument belongs to a local user. * If so, loads AVPs based on reply items returned from Radius. */ int radius_does_uri_user_exist(struct sip_msg* _m, str user) { static char msg[4096]; VALUE_PAIR *send, *received; uint32_t service; int res, extra_cnt, offset, i; send = received = 0; if (!rc_avpair_add(rh, &send, uri_attrs[SA_USER_NAME].v, user.s, user.len, 0)) { LM_ERR("in adding SA_USER_NAME\n"); return -1; } service = uri_vals[UV_CALL_CHECK].v; if (!rc_avpair_add(rh, &send, uri_attrs[SA_SERVICE_TYPE].v, &service, -1, 0)) { LM_ERR("in adding SA_SERVICE_TYPE <%u>\n", service); goto error; } /* Add extra attributes */ extra_cnt = extra2strar(uri_extra, _m, val_arr); if (extra_cnt == -1) { LM_ERR("in getting values of group extra attributes\n"); goto error; } offset = SA_STATIC_MAX; for (i = 0; i < extra_cnt; i++) { if (val_arr[i].len == -1) { /* Add integer attribute */ ADD_EXTRA_AVPAIR(uri_attrs, offset+i, &(val_arr[i].s), val_arr[i].len ); } else { /* Add string attribute */ ADD_EXTRA_AVPAIR(uri_attrs, offset+i, val_arr[i].s, val_arr[i].len ); } } if ((res = rc_auth(rh, 0, send, &received, msg)) == OK_RC) { LM_DBG("success\n"); rc_avpair_free(send); generate_avps(uri_attrs, received); rc_avpair_free(received); return 1; } else { rc_avpair_free(send); rc_avpair_free(received); #ifdef REJECT_RC if (res == REJECT_RC) { LM_DBG("rejected\n"); return -1; } else { LM_ERR("failure\n"); return -2; } #else LM_DBG("failure\n"); return -1; #endif } error: rc_avpair_free(send); return -1; }
/* * Check from Radius if URI, whose user and host parts are given as * arguments, exists. If so, loads AVPs based on reply items returned * from Radius. If use_sip_uri_host module parameter has non-zero value, * user is send in SA_USER_NAME attribute and host in SA_SIP_URI_HOST * attribute. If is has zero value, user@host is send in SA_USER_NAME * attribute. */ int radius_does_uri_user_host_exist(struct sip_msg* _m, str user, str host) { char* at, *user_host; VALUE_PAIR *send, *received; uint32_t service; static char msg[4096]; int extra_cnt, offset, i, res; send = received = 0; user_host = 0; if (!use_sip_uri_host) { /* Send user@host in SA_USER_NAME attr */ user_host = (char*)pkg_malloc(user.len + host.len + 2); if (!user_host) { LM_ERR("no more pkg memory\n"); return -1; } at = user_host; memcpy(at, user.s, user.len); at += user.len; *at = '@'; at++; memcpy(at , host.s, host.len); at += host.len; *at = '\0'; if (!rc_avpair_add(rh, &send, uri_attrs[SA_USER_NAME].v, user_host, -1, 0)) { LM_ERR("in adding SA_USER_NAME\n"); pkg_free(user_host); return -1; } } else { /* Send user in SA_USER_NAME attribute and host in SA_SIP_URI_HOST attribute */ if (!rc_avpair_add(rh, &send, uri_attrs[SA_USER_NAME].v, user.s, user.len, 0)) { LM_ERR("adding User-Name failed\n"); return -1; } if (!rc_avpair_add(rh, &send, uri_attrs[SA_SIP_URI_HOST].v, host.s, host.len, 0)) { LM_ERR("adding SIP-URI-Host failed\n"); goto error; } } service = uri_vals[UV_CALL_CHECK].v; if (!rc_avpair_add(rh, &send, uri_attrs[SA_SERVICE_TYPE].v, &service, -1, 0)) { LM_ERR("in adding SA_SERVICE_TYPE <%u>\n", service); goto error; } /* Add extra attributes */ extra_cnt = extra2strar(uri_extra, _m, val_arr); if (extra_cnt == -1) { LM_ERR("in getting values of group extra attributes\n"); goto error; } offset = SA_STATIC_MAX; for (i = 0; i < extra_cnt; i++) { if (val_arr[i].len == -1) { /* Add integer attribute */ ADD_EXTRA_AVPAIR(uri_attrs, offset+i, &(val_arr[i].s), val_arr[i].len ); } else { /* Add string attribute */ ADD_EXTRA_AVPAIR(uri_attrs, offset+i, val_arr[i].s, val_arr[i].len ); } } if ((res = rc_auth(rh, 0, send, &received, msg)) == OK_RC) { LM_DBG("success\n"); if (user_host) pkg_free(user_host); rc_avpair_free(send); generate_avps(uri_attrs, received); rc_avpair_free(received); return 1; } else { if (user_host) pkg_free(user_host); rc_avpair_free(send); rc_avpair_free(received); #ifdef REJECT_RC if (res == REJECT_RC) { LM_DBG("rejected\n"); return -1; } else { LM_ERR("failure\n"); return -2; } #else LM_DBG("failure\n"); return -1; #endif } error: rc_avpair_free(send); if (user_host) pkg_free(user_host); return -1; }
/* * Check from Radius if a user belongs to a group. User-Name is given in * first string argment that may contain pseudo variables. SIP-Group is * given in second string variable that may not contain pseudo variables. * Service-Type is Group-Check. */ int radius_is_user_in(struct sip_msg* _m, char* _user, char* _group) { str user, *group; VALUE_PAIR *send, *received; uint32_t service; static char msg[4096]; int extra_cnt, offset, i, res; send = received = 0; if ((_user == NULL) || (fixup_get_svalue(_m, (gparam_p)_user, &user) != 0)) { LM_ERR("invalid user parameter"); return -1; } if (!rc_avpair_add(rh, &send, group_attrs[SA_USER_NAME].v, user.s, user.len, 0)) { LM_ERR("in adding SA_USER_NAME\n"); return -1; } group = (str*)_group; if ((group == NULL) || (group->len == 0)) { LM_ERR("invalid group parameter"); goto error; } if (!rc_avpair_add(rh, &send, group_attrs[SA_SIP_GROUP].v, group->s, group->len, 0)) { LM_ERR("in adding SA_SIP_GROUP\n"); goto error; } service = group_vals[GV_GROUP_CHECK].v; if (!rc_avpair_add(rh, &send, group_attrs[SA_SERVICE_TYPE].v, &service, -1, 0)) { LM_ERR("in adding SA_SERVICE_TYPE <%u>\n", service); goto error; } /* Add extra attributes */ extra_cnt = extra2strar(group_extra, _m, val_arr); if (extra_cnt == -1) { LM_ERR("in getting values of group extra attributes\n"); goto error; } offset = SA_STATIC_MAX; for (i = 0; i < extra_cnt; i++) { if (val_arr[i].len == -1) { /* Add integer attribute */ ADD_EXTRA_AVPAIR(group_attrs, offset+i, &(val_arr[i].s), val_arr[i].len ); } else { /* Add string attribute */ ADD_EXTRA_AVPAIR(group_attrs, offset+i, val_arr[i].s, val_arr[i].len ); } } if ((res = rc_auth(rh, 0, send, &received, msg)) == OK_RC) { LM_DBG("success\n"); rc_avpair_free(send); generate_avps(group_attrs, received); rc_avpair_free(received); return 1; } else { rc_avpair_free(send); rc_avpair_free(received); #ifdef REJECT_RC if (res == REJECT_RC) { LM_DBG("rejected\n"); return -1; } else { LM_ERR("failure\n"); return -2; } #else LM_DBG("failure\n"); return -1; #endif } error: rc_avpair_free(send); return -1; }
/* * Loads from Radius callee's AVPs based on pvar argument. * Returns 1 if Radius request succeeded and -1 otherwise. */ int radius_load_callee_avps(struct sip_msg* _m, char* _callee, char* _s2) { str user; VALUE_PAIR *send, *received; uint32_t service; static char msg[4096]; int extra_cnt, offset, i, res; send = received = 0; if ((_callee == NULL) || (fixup_get_svalue(_m, (gparam_p)_callee, &user) != 0)) { LM_ERR("invalid callee parameter"); return -1; } if (!rc_avpair_add(rh, &send, callee_attrs[SA_USER_NAME].v, user.s, user.len, 0)) { LM_ERR("in adding SA_USER_NAME\n"); return -1; } service = callee_vals[EV_SIP_CALLEE_AVPS].v; if (!rc_avpair_add(rh, &send, callee_attrs[SA_SERVICE_TYPE].v, &service, -1, 0)) { LM_ERR("in adding SA_SERVICE_TYPE <%u>\n", service); goto error; } /* Add extra attributes */ extra_cnt = extra2strar(callee_extra, _m, val_arr); if (extra_cnt == -1) { LM_ERR("in getting values of callee extra attributes\n"); goto error; } offset = SA_STATIC_MAX; for (i = 0; i < extra_cnt; i++) { if (val_arr[i].len == -1) { /* Add integer attribute */ ADD_EXTRA_AVPAIR(callee_attrs, offset+i, &(val_arr[i].s), val_arr[i].len ); } else { /* Add string attribute */ ADD_EXTRA_AVPAIR(callee_attrs, offset+i, val_arr[i].s, val_arr[i].len ); } } if ((res = rc_auth(rh, 0, send, &received, msg)) == OK_RC) { LM_DBG("success\n"); rc_avpair_free(send); generate_avps(callee_attrs, received); rc_avpair_free(received); return 1; } else { rc_avpair_free(send); rc_avpair_free(received); #ifdef REJECT_RC if (res == REJECT_RC) { LM_DBG("rejected\n"); return -1; } else { LM_ERR("failure\n"); return -2; } #else LM_DBG("failure\n"); return -1; #endif } error: rc_avpair_free(send); return -1; }
static int load_uri_attrs(struct sip_msg* msg, unsigned long flags, fparam_t* fp) { static char rad_msg[4096]; struct sip_uri puri; str uri, did, scheme; UINT4 service; VALUE_PAIR* send, *received; send = NULL; received = NULL; if (get_str_fparam(&uri, msg, (fparam_t*)fp) != 0) { ERR("Unable to get URI\n"); return -1; } if (parse_uri(uri.s, uri.len, &puri) < 0) { ERR("Error while parsing URI '%.*s'\n", uri.len, uri.s); return -1; } if (puri.host.len) { /* domain name is present */ if (dm_get_did(&did, &puri.host) < 0) { DBG("Cannot lookup DID for domain %.*s, using default value\n", puri.host.len, ZSW(puri.host.s)); did.s = DEFAULT_DID; did.len = sizeof(DEFAULT_DID) - 1; } } else { /* domain name is missing -- can be caused by tel: URI */ DBG("There is no domain name, using default value\n"); did.s = DEFAULT_DID; did.len = sizeof(DEFAULT_DID) - 1; } uri_type_to_str(puri.type, &scheme); service = vals[V_GET_URI_ATTRS].v; if (scheme.len) { if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_SER_URI_SCHEME].v), scheme.s, scheme.len, VENDOR(attrs[A_SER_URI_SCHEME].v))) { ERR("Error while adding A_SER_URI_SCHEME\n"); goto error; } } if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_USER_NAME].v), puri.user.s, puri.user.len, VENDOR(attrs[A_USER_NAME].v))) { ERR("Error while adding A_USER_NAME\n"); goto error; } if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_SER_DID].v), did.s, did.len, VENDOR(attrs[A_SER_DID].v))) { ERR("Error while adding A_SER_DID\n"); goto error; } if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_SER_SERVICE_TYPE].v), &vals[V_GET_URI_ATTRS].v, -1, VENDOR(attrs[A_SER_SERVICE_TYPE].v))) { ERR("Error adding A_SERVICE_TYPE\n"); goto error; } if (rc_auth(rh, 0, send, &received, rad_msg) != OK_RC) { DBG("load_uri_attrs: Failure\n"); goto error; } DBG("load_uri_attrs: Success\n"); rc_avpair_free(send); if (generate_avps(flags, received) < 0) { rc_avpair_free(received); goto error; } rc_avpair_free(received); return 1; error: if (send) rc_avpair_free(send); if (received) rc_avpair_free(send); return -1; }
/* * Authorize digest credentials */ static inline int digest_authenticate(struct sip_msg* msg, fparam_t* realm, char* tname, hdr_types_t hftype) { char ha1[256]; int res; struct hdr_field* h; auth_body_t* cred; str domain, table; db1_res_t* result = NULL; int ret; cred = 0; ret = AUTH_ERROR; if(!tname) { LM_ERR("invalid table parameter\n"); return AUTH_ERROR; } table.s = tname; table.len = strlen(tname); if (get_str_fparam(&domain, msg, realm) < 0) { LM_ERR("failed to get realm value\n"); goto end; } if (domain.len==0) { LM_ERR("invalid realm parameter - empty value\n"); goto end; } LM_DBG("realm value [%.*s]\n", domain.len, domain.s); ret = auth_api.pre_auth(msg, &domain, hftype, &h, NULL); switch(ret) { case ERROR: case BAD_CREDENTIALS: LM_DBG("error or bad credentials\n"); ret = AUTH_ERROR; goto end; case CREATE_CHALLENGE: LM_ERR("CREATE_CHALLENGE is not a valid state\n"); ret = AUTH_ERROR; goto end; case DO_RESYNCHRONIZATION: LM_ERR("DO_RESYNCHRONIZATION is not a valid state\n"); ret = AUTH_ERROR; goto end; case NOT_AUTHENTICATED: LM_DBG("not authenticated\n"); ret = AUTH_ERROR; goto end; case DO_AUTHENTICATION: break; case AUTHENTICATED: ret = AUTH_OK; goto end; } cred = (auth_body_t*)h->parsed; res = get_ha1(&cred->digest.username, &domain, &table, ha1, &result); if (res < 0) { /* Error while accessing the database */ ret = AUTH_ERROR; goto end; } if (res > 0) { /* Username not found in the database */ ret = AUTH_USER_UNKNOWN; goto end; } /* Recalculate response, it must be same to authorize successfully */ ret = auth_api.check_response(&(cred->digest), &msg->first_line.u.request.method, ha1); if(ret==AUTHENTICATED) { ret = AUTH_OK; switch(auth_api.post_auth(msg, h)) { case AUTHENTICATED: generate_avps(result); break; default: ret = AUTH_ERROR; break; } } else { if(ret==NOT_AUTHENTICATED) ret = AUTH_INVALID_PASSWORD; else ret = AUTH_ERROR; } end: if(result) auth_dbf.free_result(auth_db_handle, result); return ret; }
/* * Authorize digest credentials */ static inline int authenticate(struct sip_msg* msg, str* realm, hdr_types_t hftype) { int res; auth_result_t ret; struct hdr_field* h; auth_body_t* cred; str* uri; struct sip_uri puri; str user, did; VALUE_PAIR* received; cred = 0; ret = -1; user.s = 0; received = NULL; switch(auth_api.pre_auth(msg, realm, hftype, &h, NULL)) { default: BUG("unexpected reply '%d'.\n", auth_api.pre_auth(msg, realm, hftype, &h, NULL)); #ifdef EXTRA_DEBUG abort(); #endif case ERROR: case BAD_CREDENTIALS: ret = -3; goto end; case NOT_AUTHENTICATED: ret = -1; goto end; case DO_AUTHENTICATION: break; case AUTHENTICATED: ret = 1; goto end; } cred = (auth_body_t*)h->parsed; if (use_did) { if (msg->REQ_METHOD == METHOD_REGISTER) { ret = get_to_did(&did, msg); } else { ret = get_from_did(&did, msg); } if (ret == 0) { did.s = DEFAULT_DID; did.len = sizeof(DEFAULT_DID) - 1; } } else { did.len = 0; did.s = 0; } if (get_uri(msg, &uri) < 0) { LOG(L_ERR, "authorize(): From/To URI not found\n"); ret = -1; goto end; } if (parse_uri(uri->s, uri->len, &puri) < 0) { LOG(L_ERR, "authorize(): Error while parsing From/To URI\n"); ret = -1; goto end; } user.s = (char *)pkg_malloc(puri.user.len); if (user.s == NULL) { LOG(L_ERR, "authorize: No memory left\n"); ret = -1; goto end; } un_escape(&(puri.user), &user); res = radius_authorize_sterman(&received, msg, &cred->digest, &msg->first_line.u.request.method, &user); if (res == 1) { switch(auth_api.post_auth(msg, h)) { case ERROR: case BAD_CREDENTIALS: ret = -2; break; case NOT_AUTHENTICATED: ret = -1; break; case AUTHENTICATED: if (generate_avps(received) < 0) { ret = -1; break; } ret = 1; break; default: ret = -1; break; } } else { ret = -1; } end: if (received) rc_avpair_free(received); if (user.s) pkg_free(user.s); if (ret < 0) { if (auth_api.build_challenge(msg, (cred ? cred->stale : 0), realm, NULL, NULL, hftype) < 0) { ERR("Error while creating challenge\n"); ret = -2; } } return ret; }
/* * This function creates and submits radius authentication request as per * draft-sterman-aaa-sip-00.txt. In addition, _user parameter is included * in the request as value of a SER specific attribute type SIP-URI-User, * which can be be used as a check item in the request. Service type of * the request is Authenticate-Only. */ int radius_authorize_sterman(struct sip_msg* _msg, dig_cred_t* _cred, str* _method, str* _user) { static char msg[4096]; VALUE_PAIR *send, *received; uint32_t service; str method, user, user_name; str *ruri; int extra_cnt, offset, i; send = received = 0; if (!(_cred && _method && _user)) { LM_ERR("invalid parameter value\n"); return -1; } method = *_method; user = *_user; /* * Add all the user digest parameters according to the qop defined. * Most devices tested only offer support for the simplest digest. */ if (_cred->username.domain.len || !append_realm_to_username) { if (!rc_avpair_add(rh, &send, attrs[A_USER_NAME].v, _cred->username.whole.s, _cred->username.whole.len, 0)) { LM_ERR("unable to add User-Name attribute\n"); goto err; } } else { user_name.len = _cred->username.user.len + _cred->realm.len + 1; user_name.s = pkg_malloc(user_name.len); if (!user_name.s) { LM_ERR("no pkg memory left\n"); return -3; } memcpy(user_name.s, _cred->username.whole.s, _cred->username.whole.len); user_name.s[_cred->username.whole.len] = '@'; memcpy(user_name.s + _cred->username.whole.len + 1, _cred->realm.s, _cred->realm.len); if (!rc_avpair_add(rh, &send, attrs[A_USER_NAME].v, user_name.s, user_name.len, 0)) { LM_ERR("unable to add User-Name attribute\n"); pkg_free(user_name.s); goto err; } pkg_free(user_name.s); } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_USER_NAME].v, _cred->username.whole.s, _cred->username.whole.len, 0)) { LM_ERR("unable to add Digest-User-Name attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_REALM].v, _cred->realm.s, _cred->realm.len, 0)) { LM_ERR("unable to add Digest-Realm attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_NONCE].v, _cred->nonce.s, _cred->nonce.len, 0)) { LM_ERR("unable to add Digest-Nonce attribute\n"); goto err; } if (use_ruri_flag < 0 || isflagset(_msg, use_ruri_flag) != 1) { ruri = &_cred->uri; } else { ruri = GET_RURI(_msg); } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_URI].v, ruri->s, ruri->len, 0)) { LM_ERR("unable to add Digest-URI attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_METHOD].v, method.s, method.len, 0)) { LM_ERR("unable to add Digest-Method attribute\n"); goto err; } /* * Add the additional authentication fields according to the QOP. */ if (_cred->qop.qop_parsed == QOP_AUTH) { if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_QOP].v, "auth", 4, 0)) { LM_ERR("unable to add Digest-QOP attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_NONCE_COUNT].v, _cred->nc.s, _cred->nc.len, 0)) { LM_ERR("unable to add Digest-CNonce-Count attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_CNONCE].v, _cred->cnonce.s, _cred->cnonce.len, 0)) { LM_ERR("unable to add Digest-CNonce attribute\n"); goto err; } } else if (_cred->qop.qop_parsed == QOP_AUTHINT) { if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_QOP].v, "auth-int", 8, 0)) { LM_ERR("unable to add Digest-QOP attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_NONCE_COUNT].v, _cred->nc.s, _cred->nc.len, 0)) { LM_ERR("unable to add Digest-Nonce-Count attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_CNONCE].v, _cred->cnonce.s, _cred->cnonce.len, 0)) { LM_ERR("unable to add Digest-CNonce attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_BODY_DIGEST].v, _cred->opaque.s, _cred->opaque.len, 0)) { LM_ERR("unable to add Digest-Body-Digest attribute\n"); goto err; } } else { /* send nothing for qop == "" */ } /* Add the response... What to calculate against... */ if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_RESPONSE].v, _cred->response.s, _cred->response.len, 0)) { LM_ERR("unable to add Digest-Response attribute\n"); goto err; } /* Indicate the service type, Authenticate only in our case */ service = vals[V_SIP_SESSION].v; if (!rc_avpair_add(rh, &send, attrs[A_SERVICE_TYPE].v, &service, -1, 0)) { LM_ERR("unable to add Service-Type attribute\n"); goto err; } /* Add SIP URI as a check item */ if (!rc_avpair_add(rh,&send,attrs[A_SIP_URI_USER].v,user.s,user.len,0)) { LM_ERR("unable to add Sip-URI-User attribute\n"); goto err; } if (attrs[A_CISCO_AVPAIR].n != NULL) { if (add_cisco_vsa(&send, _msg)) { goto err; } } /* Add extra attributes */ extra_cnt = extra2strar(auth_extra, _msg, val_arr); if (extra_cnt == -1) { LM_ERR("in getting values of extra attributes\n"); goto err; } offset = A_MAX; for (i = 0; i < extra_cnt; i++) { if (val_arr[i].len == -1) { /* Add integer attribute */ ADD_EXTRA_AVPAIR(attrs, offset+i, &(val_arr[i].s), val_arr[i].len ); } else { /* Add string attribute */ ADD_EXTRA_AVPAIR(attrs, offset+i, val_arr[i].s, val_arr[i].len ); } } /* Send request */ if ((i = rc_auth(rh, SIP_PORT, send, &received, msg)) == OK_RC) { LM_DBG("Success\n"); rc_avpair_free(send); send = 0; generate_avps(received); rc_avpair_free(received); return 1; } else { #ifdef REJECT_RC if (i == REJECT_RC) { LM_DBG("Failure\n"); goto err; } #endif LM_ERR("authorization failed. RC auth returned %d\n", i); } err: if (send) rc_avpair_free(send); if (received) rc_avpair_free(received); return -1; }
/* * Authorize digest credentials and set the pointer to used hdr */ static int digest_authenticate_hdr(sip_msg_t* msg, str *realm, str *table, hdr_types_t hftype, str *method, hdr_field_t **ahdr) { char ha1[256]; int res; struct hdr_field* h; auth_body_t* cred; db1_res_t* result = NULL; int ret; cred = 0; ret = AUTH_ERROR; ret = auth_api.pre_auth(msg, realm, hftype, &h, NULL); switch(ret) { case NONCE_REUSED: LM_DBG("nonce reused"); ret = AUTH_NONCE_REUSED; goto end; case STALE_NONCE: LM_DBG("stale nonce\n"); ret = AUTH_STALE_NONCE; goto end; case NO_CREDENTIALS: LM_DBG("no credentials\n"); ret = AUTH_NO_CREDENTIALS; goto end; case ERROR: case BAD_CREDENTIALS: LM_DBG("error or bad credentials\n"); ret = AUTH_ERROR; goto end; case CREATE_CHALLENGE: LM_ERR("CREATE_CHALLENGE is not a valid state\n"); ret = AUTH_ERROR; goto end; case DO_RESYNCHRONIZATION: LM_ERR("DO_RESYNCHRONIZATION is not a valid state\n"); ret = AUTH_ERROR; goto end; case NOT_AUTHENTICATED: LM_DBG("not authenticated\n"); ret = AUTH_ERROR; goto end; case DO_AUTHENTICATION: break; case AUTHENTICATED: ret = AUTH_OK; goto end; } cred = (auth_body_t*)h->parsed; if(ahdr!=NULL) *ahdr = h; res = get_ha1(&cred->digest.username, realm, table, ha1, &result); if (res < 0) { /* Error while accessing the database */ ret = AUTH_ERROR; goto end; } if (res > 0) { /* Username not found in the database */ ret = AUTH_USER_UNKNOWN; goto end; } /* Recalculate response, it must be same to authorize successfully */ ret = auth_api.check_response(&(cred->digest), method, ha1); if(ret==AUTHENTICATED) { ret = AUTH_OK; switch(auth_api.post_auth(msg, h, ha1)) { case AUTHENTICATED: generate_avps(msg, result); break; default: ret = AUTH_ERROR; break; } } else { if(ret==NOT_AUTHENTICATED) ret = AUTH_INVALID_PASSWORD; else ret = AUTH_ERROR; } end: if(result) auth_dbf.free_result(auth_db_handle, result); return ret; }
/* * Authorize digest credentials */ static inline int authorize(struct sip_msg* _m, str* _realm, char* _table, hdr_types_t _hftype) { char ha1[256]; int res; struct hdr_field* h; auth_body_t* cred; auth_result_t ret; str domain; db_res_t* result; domain = *_realm; ret = auth_api.pre_auth(_m, &domain, _hftype, &h); switch(ret) { case ERROR: return 0; case NOT_AUTHORIZED: return -1; case DO_AUTHORIZATION: break; case AUTHORIZED: return 1; } cred = (auth_body_t*)h->parsed; res = get_ha1(&cred->digest.username, &domain, _table, ha1, &result); if (res < 0) { /* Error while accessing the database */ if (sl_reply(_m, (char*)500, MESSAGE_500) == -1) { LOG(L_ERR, "authorize(): Error while sending 500 reply\n"); } return 0; } if (res > 0) { /* Username not found in the database */ auth_dbf.free_result(auth_db_handle, result); return -1; } /* Recalculate response, it must be same to authorize successfully */ if (!check_response(&(cred->digest),&_m->first_line.u.request.method,ha1)) { ret = auth_api.post_auth(_m, h); switch(ret) { case ERROR: auth_dbf.free_result(auth_db_handle, result); return 1; case NOT_AUTHORIZED: auth_dbf.free_result(auth_db_handle, result); return -1; case AUTHORIZED: generate_avps(result); auth_dbf.free_result(auth_db_handle, result); return 1; default: auth_dbf.free_result(auth_db_handle, result); return -1; } } auth_dbf.free_result(auth_db_handle, result); return -1; }
/* * Authorize digest credentials */ static inline int authorize(struct sip_msg* _m, gparam_p _realm, char* _table, hdr_types_t _hftype) { char ha1[256]; int res; struct hdr_field* h; auth_body_t* cred; auth_result_t ret; str domain, table; db_res_t* result = NULL; if(!_table) { LM_ERR("invalid table parameter\n"); return -1; } table.s = _table; table.len = strlen(_table); if(fixup_get_svalue(_m, _realm, &domain)!=0) { LM_ERR("invalid realm parameter\n"); return AUTH_ERROR; } if (domain.len==0) domain.s = 0; ret = auth_api.pre_auth(_m, &domain, _hftype, &h); if (ret != DO_AUTHORIZATION) return ret; cred = (auth_body_t*)h->parsed; res = get_ha1(&cred->digest.username, &domain, &table, ha1, &result); if (res < 0) { /* Error while accessing the database */ if (sigb.reply(_m, 500, &auth_500_err, NULL) == -1) { LM_ERR("failed to send 500 reply\n"); } return ERROR; } if (res > 0) { /* Username not found in the database */ auth_dbf.free_result(auth_db_handle, result); return USER_UNKNOWN; } /* Recalculate response, it must be same to authorize successfully */ if (!auth_api.check_response(&(cred->digest), &_m->first_line.u.request.method, ha1)) { ret = auth_api.post_auth(_m, h); if (ret == AUTHORIZED) generate_avps(result); auth_dbf.free_result(auth_db_handle, result); return ret; } auth_dbf.free_result(auth_db_handle, result); return INVALID_PASSWORD; }
/* * Authenticate digest credentials * Returns: * -3 -- Bad Request * -2 -- Error while checking credentials (such as malformed message or database problem) * -1 -- Authentication failed * 1 -- Authentication successful */ static inline int authenticate(struct sip_msg* msg, str* realm, authdb_table_info_t *table, hdr_types_t hftype) { char ha1[256]; int res, ret; db_rec_t *row; struct hdr_field* h; auth_body_t* cred; db_res_t* result; str did; cred = 0; result = 0; ret = -1; switch(auth_api.pre_auth(msg, realm, hftype, &h, NULL)) { case ERROR: case BAD_CREDENTIALS: ret = -3; goto end; case CREATE_CHALLENGE: ERR("auth_db:authenticate: CREATE_CHALLENGE is not a valid state\n"); ret = -2; goto end; case DO_RESYNCHRONIZATION: ERR("auth_db:authenticate: DO_RESYNCHRONIZATION is not a valid state\n"); ret = -2; goto end; case NOT_AUTHENTICATED: ret = -1; goto end; case DO_AUTHENTICATION: break; case AUTHENTICATED: ret = 1; goto end; } cred = (auth_body_t*)h->parsed; if (use_did) { if (msg->REQ_METHOD == METHOD_REGISTER) { ret = get_to_did(&did, msg); } else { ret = get_from_did(&did, msg); } if (ret == 0) { did.s = DEFAULT_DID; did.len = sizeof(DEFAULT_DID) - 1; } } else { did.len = 0; did.s = 0; } if (check_all) { res = check_all_ha1(msg, h, &(cred->digest), &msg->first_line.u.request.method, &did, realm, table, &result); if (res < 0) { ret = -2; goto end; } else if (res > 0) { ret = -1; goto end; } else { ret = 1; goto end; } } else { res = get_ha1(&cred->digest.username, &did, realm, table, ha1, &result, &row); if (res < 0) { ret = -2; goto end; } if (res > 0) { /* Username not found in the database */ ret = -1; goto end; } } /* Recalculate response, it must be same to authorize successfully */ if (!check_response(&(cred->digest), &msg->first_line.u.request.method, ha1)) { switch(auth_api.post_auth(msg, h)) { case ERROR: case BAD_CREDENTIALS: ret = -2; break; case NOT_AUTHENTICATED: ret = -1; break; case AUTHENTICATED: generate_avps(result, row); ret = 1; break; default: ret = -1; break; } } else { ret = -1; } end: if (result) db_res_free(result); if (ret < 0) { if (auth_api.build_challenge(msg, (cred ? cred->stale : 0), realm, NULL, NULL, hftype) < 0) { ERR("Error while creating challenge\n"); ret = -2; } } return ret; }
/* this is a dirty work around to check the credentials of all users, * if the database query returned more then one result * * Fills res (which must be db_free'd afterwards if the call was succesfull) * returns 0 on success, 1 on no match (?) * and -1 on error (memory, db a.s.o). * WARNING: if -1 is returned res _must_ _not_ be freed (it's empty) * */ static inline int check_all_ha1(struct sip_msg* msg, struct hdr_field* hdr, dig_cred_t* dig, str* method, str* did, str* realm, authdb_table_info_t *table_info, db_res_t** res) { char ha1[256]; db_rec_t *row; str result; db_cmd_t *q; if (calc_ha1) { q = table_info->query_password; DBG("querying plain password\n"); } else { if (dig->username.domain.len) { q = table_info->query_pass2; DBG("querying ha1b\n"); } else { q = table_info->query_pass; DBG("querying ha1\n"); } } q->match[0].v.lstr = dig->username.user; if (dig->username.domain.len) q->match[1].v.lstr = dig->username.domain; else q->match[1].v.lstr = *realm; if (use_did) q->match[2].v.lstr = *did; if (db_exec(res, q) < 0 ) { ERR("Error while querying database\n"); } if (*res) row = db_first(*res); else row = NULL; while (row) { if (IS_NULL(row->fld[0]) || IS_NULL(row->fld[1])) { LOG(L_ERR, "auth_db:check_all_ha1: Credentials for '%.*s'@'%.*s' contain NULL value, skipping\n", dig->username.user.len, ZSW(dig->username.user.s), realm->len, ZSW(realm->s)); } else { if (row->fld[1].v.int4 & DB_DISABLED) { /* disabled rows ignored */ } else { if (row->fld[1].v.int4 & DB_LOAD_SER) { result.s = row->fld[0].v.cstr; result.len = strlen(result.s); if (calc_ha1) { /* Only plaintext passwords are stored in database, * we have to calculate HA1 */ auth_api.calc_HA1(HA_MD5, &(dig->username.whole), realm, &result, 0, 0, ha1); DBG("auth_db:check_all_ha1: HA1 string calculated: %s\n", ha1); } else { memcpy(ha1, result.s, result.len); ha1[result.len] = '\0'; } if (!check_response(dig, method, ha1)) { if (auth_api.post_auth(msg, hdr) == AUTHENTICATED) { generate_avps(*res, row); return 0; } } } } } row = db_next(*res); } if (!row) { DBG("auth_db:check_all_ha1: Credentials for '%.*s'@'%.*s' not found", dig->username.user.len, ZSW(dig->username.user.s), realm->len, ZSW(realm->s)); } return 1; }