static int auth_challenge(struct sip_msg *msg, char *p1, char *p2, int hftype) { int flags = 0; str realm = {0, 0}; int ret; str hf = {0, 0}; struct qp *qop = NULL; ret = -1; if (get_str_fparam(&realm, msg, (fparam_t*)p1) < 0) { LM_ERR("failed to get realm value\n"); goto error; } if(realm.len==0) { LM_ERR("invalid realm value - empty content\n"); goto error; } if (get_int_fparam(&flags, msg, (fparam_t*)p2) < 0) { LM_ERR("invalid flags value\n"); goto error; } if(flags&2) { qop = &auth_qauthint; } else if(flags&1) { qop = &auth_qauth; } if (get_challenge_hf(msg, 0, &realm, NULL, NULL, qop, hftype, &hf) < 0) { ERR("Error while creating challenge\n"); ret = -2; goto error; } ret = 1; switch(hftype) { case HDR_AUTHORIZATION_T: if(auth_send_reply(msg, 401, "Unauthorized", hf.s, hf.len) <0 ) ret = -3; break; case HDR_PROXYAUTH_T: if(auth_send_reply(msg, 407, "Proxy Authentication Required", hf.s, hf.len) <0 ) ret = -3; break; } if(hf.s) pkg_free(hf.s); return ret; error: if(hf.s) pkg_free(hf.s); if(!(flags&4)) { if(auth_send_reply(msg, 500, "Internal Server Error", 0, 0) <0 ) ret = -4; } return ret; }
int auth_challenge_helper(struct sip_msg *msg, str *realm, int flags, int hftype, str *res) { int ret, stale; str hf = {0, 0}; struct qp *qop = NULL; ret = -1; if(flags&2) { qop = &auth_qauthint; } else if(flags&1) { qop = &auth_qauth; } if (flags & 16) { stale = 1; } else { stale = 0; } if (get_challenge_hf(msg, stale, realm, NULL, NULL, qop, hftype, &hf) < 0) { ERR("Error while creating challenge\n"); ret = -2; goto error; } ret = 1; if(res!=NULL) { *res = hf; return ret; } switch(hftype) { case HDR_AUTHORIZATION_T: if(auth_send_reply(msg, 401, "Unauthorized", hf.s, hf.len) <0 ) ret = -3; break; case HDR_PROXYAUTH_T: if(auth_send_reply(msg, 407, "Proxy Authentication Required", hf.s, hf.len) <0 ) ret = -3; break; } if(hf.s) pkg_free(hf.s); return ret; error: if(hf.s) pkg_free(hf.s); if(!(flags&4)) { if(auth_send_reply(msg, 500, "Internal Server Error", 0, 0) <0 ) ret = -4; } return ret; }
/** * Create {WWW,Proxy}-Authenticate header field * @param nonce nonce value * @param algorithm algorithm value * @return -1 on error, 0 on success * * The result is stored in an attribute. * If nonce is not null that it is used, instead of call calc_nonce. * If algorithm is not null that it is used irrespective of _PRINT_MD5 * The value of 'qop' module parameter is used. * * Major usage of nonce and algorithm params is AKA authentication. */ int build_challenge_hf(struct sip_msg* msg, int stale, str* realm, str* nonce, str* algorithm, int hftype) { str hf = {0, 0}; avp_value_t val; int ret; ret = get_challenge_hf(msg, stale, realm, nonce, algorithm, &auth_qop, hftype, &hf); if(ret < 0) return ret; val.s = hf; if(add_avp(challenge_avpid.flags | AVP_VAL_STR, challenge_avpid.name, val) < 0) { ERR("auth: Error while creating attribute with challenge\n"); pkg_free(hf.s); return -1; } pkg_free(hf.s); return 0; }
/** * @brief do WWW-Digest authentication with password taken from cfg var */ static int pv_authenticate(struct sip_msg *msg, char *p1, char *p2, char *p3, int hftype) { int flags = 0; str realm = {0, 0}; str passwd = {0, 0}; struct hdr_field* h; auth_body_t* cred; int ret; str hf = {0, 0}; avp_value_t val; static char ha1[256]; struct qp *qop = NULL; cred = 0; ret = AUTH_ERROR; if (get_str_fparam(&realm, msg, (fparam_t*)p1) < 0) { LM_ERR("failed to get realm value\n"); goto error; } if(realm.len==0) { LM_ERR("invalid realm value - empty content\n"); goto error; } if (get_str_fparam(&passwd, msg, (fparam_t*)p2) < 0) { LM_ERR("failed to get passwd value\n"); goto error; } if(passwd.len==0) { LM_ERR("invalid password value - empty content\n"); goto error; } if (get_int_fparam(&flags, msg, (fparam_t*)p3) < 0) { LM_ERR("invalid flags value\n"); goto error; } switch(pre_auth(msg, &realm, hftype, &h, NULL)) { 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; /* compute HA1 if needed */ if ((flags&1)==0) { /* Plaintext password is stored in PV, calculate HA1 */ calc_HA1(HA_MD5, &cred->digest.username.whole, &realm, &passwd, 0, 0, ha1); LM_DBG("HA1 string calculated: %s\n", ha1); } else { memcpy(ha1, passwd.s, passwd.len); ha1[passwd.len] = '\0'; } /* Recalculate response, it must be same to authorize successfully */ ret = auth_check_response(&(cred->digest), &msg->first_line.u.request.method, ha1); if(ret==AUTHENTICATED) { ret = AUTH_OK; switch(post_auth(msg, h)) { case AUTHENTICATED: break; default: ret = AUTH_ERROR; break; } } else { if(ret==NOT_AUTHENTICATED) ret = AUTH_INVALID_PASSWORD; else ret = AUTH_ERROR; } end: if (ret < 0) { /* check if required to add challenge header as avp */ if(!(flags&14)) return ret; if(flags&8) { qop = &auth_qauthint; } else if(flags&4) { qop = &auth_qauth; } if (get_challenge_hf(msg, (cred ? cred->stale : 0), &realm, NULL, NULL, qop, hftype, &hf) < 0) { ERR("Error while creating challenge\n"); ret = AUTH_ERROR; } else { val.s = hf; if(add_avp(challenge_avpid.flags | AVP_VAL_STR, challenge_avpid.name, val) < 0) { LM_ERR("Error while creating attribute with challenge\n"); ret = AUTH_ERROR; } pkg_free(hf.s); } } error: return ret; }
/** * @brief do WWW-Digest authentication with password taken from cfg var */ int pv_authenticate(struct sip_msg *msg, str *realm, str *passwd, int flags, int hftype, str *method) { struct hdr_field* h; auth_body_t* cred; int ret; str hf = {0, 0}; avp_value_t val; static char ha1[256]; struct qp *qop = NULL; cred = 0; ret = AUTH_ERROR; switch(pre_auth(msg, realm, hftype, &h, NULL)) { 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; /* compute HA1 if needed */ if ((flags&1)==0) { /* Plaintext password is stored in PV, calculate HA1 */ calc_HA1(HA_MD5, &cred->digest.username.whole, realm, passwd, 0, 0, ha1); LM_DBG("HA1 string calculated: %s\n", ha1); } else { memcpy(ha1, passwd->s, passwd->len); ha1[passwd->len] = '\0'; } /* Recalculate response, it must be same to authorize successfully */ ret = auth_check_response(&(cred->digest), method, ha1); if(ret==AUTHENTICATED) { ret = AUTH_OK; switch(post_auth(msg, h)) { case AUTHENTICATED: break; default: ret = AUTH_ERROR; break; } } else { if(ret==NOT_AUTHENTICATED) ret = AUTH_INVALID_PASSWORD; else ret = AUTH_ERROR; } end: if (ret < 0) { /* check if required to add challenge header as avp */ if(!(flags&14)) return ret; if(flags&8) { qop = &auth_qauthint; } else if(flags&4) { qop = &auth_qauth; } if (get_challenge_hf(msg, (cred ? cred->stale : 0), realm, NULL, NULL, qop, hftype, &hf) < 0) { ERR("Error while creating challenge\n"); ret = AUTH_ERROR; } else { val.s = hf; if(add_avp(challenge_avpid.flags | AVP_VAL_STR, challenge_avpid.name, val) < 0) { LM_ERR("Error while creating attribute with challenge\n"); ret = AUTH_ERROR; } pkg_free(hf.s); } } return ret; }