int uac_auth( struct sip_msg *msg) { struct authenticate_body *auth = NULL; static struct authenticate_nc_cnonce auth_nc_cnonce; struct uac_credential *crd; int code, branch; unsigned int new_cseq; struct sip_msg *rpl; struct cell *t; HASHHEX response; str *new_hdr; str param; char *p; struct dlg_cell *dlg; /* get transaction */ t = uac_tmb.t_gett(); if (t==T_UNDEFINED || t==T_NULL_CELL) { LM_CRIT("no current transaction found\n"); goto error; } /* get the selected branch */ branch = uac_tmb.t_get_picked(); if (branch<0) { LM_CRIT("no picked branch (%d)\n",branch); goto error; } rpl = t->uac[branch].reply; code = t->uac[branch].last_received; LM_DBG("picked reply is %p, code %d\n",rpl,code); if (rpl==0) { LM_CRIT("empty reply on picked branch\n"); goto error; } if (rpl==FAKED_REPLY) { LM_ERR("cannot process a FAKED reply\n"); goto error; } if (code==WWW_AUTH_CODE) { if (0 == parse_www_authenticate_header(rpl)) auth = get_www_authenticate(rpl); } else if (code==PROXY_AUTH_CODE) { if (0 == parse_proxy_authenticate_header(rpl)) auth = get_proxy_authenticate(rpl); } if (auth == NULL) { LM_ERR("Unable to extract authentication info\n"); goto error; } /* can we authenticate this realm? */ /* look into existing credentials */ crd = uac_auth_api._lookup_realm( &auth->realm ); /* found? */ if (crd==0) { LM_DBG("no credential for realm \"%.*s\"\n", auth->realm.len, auth->realm.s); goto error; } /* do authentication */ uac_auth_api._do_uac_auth( &msg->first_line.u.request.method, &t->uac[branch].uri, crd, auth, &auth_nc_cnonce, response); /* build the authorization header */ new_hdr = uac_auth_api._build_authorization_hdr( code, &t->uac[branch].uri, crd, auth, &auth_nc_cnonce, response); if (new_hdr==0) { LM_ERR("failed to build authorization hdr\n"); goto error; } /* so far, so good -> add the header and set the proper RURI */ if (apply_urihdr_changes( msg, &t->uac[branch].uri, new_hdr)<0) { LM_ERR("failed to apply changes\n"); pkg_free(new_hdr->s); new_hdr->s = NULL; new_hdr->len = 0; goto error; } if ( (new_cseq = apply_cseq_op(msg,1)) < 0) { LM_WARN("Failure to increment the CSEQ header - continue \n"); goto error; } /* only register the TMCB once per transaction */ if (!(msg->msg_flags & FL_USE_UAC_CSEQ || t->uas.request->msg_flags & FL_USE_UAC_CSEQ)) { if (uac_tmb.register_tmcb( msg, 0, TMCB_RESPONSE_FWDED, apply_cseq_decrement,0,0)!=1) { LM_ERR("Failed to register TMCB response fwded - continue \n"); goto error; } } if (dlg_api.get_dlg && (dlg = dlg_api.get_dlg())) { /* dlg->legs[dlg->legs_no[DLG_LEGS_USED]-1].last_gen_cseq = new_cseq; */ dlg->flags |= DLG_FLAG_CSEQ_ENFORCE; } else { param.len=rr_uac_cseq_param.len+3; param.s=pkg_malloc(param.len); if (!param.s) { LM_ERR("No more pkg mem \n"); goto error; } p = param.s; *p++=';'; memcpy(p,rr_uac_cseq_param.s,rr_uac_cseq_param.len); p+=rr_uac_cseq_param.len; *p++='='; *p++='1'; if (uac_rrb.add_rr_param( msg, ¶m)!=0) { LM_ERR("add_RR_param failed\n"); pkg_free(param.s); goto error; } pkg_free(param.s); } msg->msg_flags |= FL_USE_UAC_CSEQ; t->uas.request->msg_flags |= FL_USE_UAC_CSEQ; return 0; error: return -1; }
void reg_tm_cback(struct cell *t, int type, struct tmcb_params *ps) { struct sip_msg *msg; reg_tm_cb_t *cb_param; int statuscode = 0; unsigned int exp = 0; reg_record_t *rec; struct hdr_field *c_ptr, *head_contact; struct uac_credential crd; contact_t *contact; struct authenticate_body *auth = NULL; static struct authenticate_nc_cnonce auth_nc_cnonce; HASHHEX response; str *new_hdr; time_t now; if(ps==NULL || ps->rpl==NULL) { LM_ERR("wrong ps parameter\n"); return; } if(ps->param==NULL || *ps->param==NULL) { LM_ERR("null callback parameter\n"); return; } cb_param = (reg_tm_cb_t *)*ps->param; if(cb_param->uac == NULL) { LM_ERR("null record\n"); return; } statuscode = ps->code; now = time(0); LM_DBG("tm [%p] notification cb for %s [%d] reply at [%d]\n", t, (ps->rpl==FAKED_REPLY)?"FAKED_REPLY":"", statuscode, (unsigned int)now); if(statuscode<200) return; lock_get(®_htable[cb_param->hash_index].lock); rec = reg_htable[cb_param->hash_index].first; while(rec) { if (rec==cb_param->uac) { break; } rec = rec->next; } if(!rec) { LM_ERR("record [%p] not found on hash index [%d]\n", cb_param->uac, cb_param->hash_index); lock_release(®_htable[cb_param->hash_index].lock); return; } reg_print_record(rec); switch(statuscode) { case 200: msg = ps->rpl; if(msg==FAKED_REPLY) { LM_ERR("FAKED_REPLY\n"); goto done; } if (parse_headers(msg, HDR_EOH_F, 0) == -1) { LM_ERR("failed to parse headers\n"); goto done; } if (msg->contact) { c_ptr = msg->contact; while(c_ptr) { if (c_ptr->type == HDR_CONTACT_T) { if (!c_ptr->parsed && (parse_contact(c_ptr)<0)) { LM_ERR("failed to parse Contact body\n"); goto done; } } c_ptr = c_ptr->next; } } else { LM_ERR("No contact header in received 200ok\n"); goto done; } head_contact = msg->contact; contact = ((contact_body_t*)msg->contact->parsed)->contacts; while (contact) { /* Check for binding */ if (contact->uri.len==rec->contact_uri.len && strncmp(contact->uri.s,rec->contact_uri.s,contact->uri.len)==0){ if (contact->expires && contact->expires->body.len) { if (str2int(&contact->expires->body, &exp)<0) { LM_ERR("Unable to extract expires from [%.*s]" " for binding [%.*s]\n", contact->expires->body.len, contact->expires->body.s, contact->uri.len, contact->uri.s); } else { rec->expires = exp; } } break; } /* get the next contact */ if (contact->next == NULL) { contact = NULL; c_ptr = head_contact->next; while(c_ptr) { if (c_ptr->type == HDR_CONTACT_T) { head_contact = c_ptr; contact = ((contact_body_t*)c_ptr->parsed)->contacts; break; } c_ptr = c_ptr->next; } } else { contact = contact->next; } } rec->state = REGISTERED_STATE; rec->registration_timeout = now + rec->expires - timer_interval; break; case WWW_AUTH_CODE: case PROXY_AUTH_CODE: msg = ps->rpl; if(msg==FAKED_REPLY) { LM_ERR("FAKED_REPLY\n"); goto done; } if (rec->auth_user.s==NULL || rec->auth_user.len==0 || rec->auth_password.s==NULL || rec->auth_password.len==0) { LM_ERR("Credentials not provisioned\n"); rec->state = WRONG_CREDENTIALS_STATE; rec->registration_timeout = 0; lock_release(®_htable[cb_param->hash_index].lock); return; } if (statuscode==WWW_AUTH_CODE) { if (0 == parse_www_authenticate_header(msg)) auth = get_www_authenticate(msg); } else if (statuscode==PROXY_AUTH_CODE) { if (0 == parse_proxy_authenticate_header(msg)) auth = get_proxy_authenticate(msg); } if (auth == NULL) { LM_ERR("Unable to extract authentication info\n"); goto done; } LM_DBG("flags=[%d] realm=[%.*s] domain=[%.*s] nonce=[%.*s]" " opaque=[%.*s] qop=[%.*s]\n", auth->flags, auth->realm.len, auth->realm.s, auth->domain.len, auth->domain.s, auth->nonce.len, auth->nonce.s, auth->opaque.len, auth->opaque.s, auth->qop.len, auth->qop.s); switch(rec->state) { case REGISTERING_STATE: break; case AUTHENTICATING_STATE: /* We already sent an authenticated REGISTER and we are still challanged! */ LM_ERR("Wrong credentials for \n"); rec->state = WRONG_CREDENTIALS_STATE; rec->registration_timeout = 0; lock_release(®_htable[cb_param->hash_index].lock); return; default: LM_ERR("Unexpected [%d] notification cb in state [%d]\n", statuscode, rec->state); goto done; } /* perform authentication */ if (auth->realm.s && auth->realm.len) { crd.realm.s = auth->realm.s; crd.realm.len = auth->realm.len; } else { LM_ERR("No realm found\n"); goto done; } crd.user.s = rec->auth_user.s; crd.user.len = rec->auth_user.len; crd.passwd.s = rec->auth_password.s; crd.passwd.len = rec->auth_password.len; memset(&auth_nc_cnonce, 0, sizeof(struct authenticate_nc_cnonce)); uac_auth_api._do_uac_auth(®ister_method, &rec->td.rem_target, &crd, auth, &auth_nc_cnonce, response); new_hdr = uac_auth_api._build_authorization_hdr(statuscode, &rec->td.rem_target, &crd, auth, &auth_nc_cnonce, response); if (!new_hdr) { LM_ERR("failed to build authorization hdr\n"); goto done; } if(send_register(cb_param->hash_index, rec, new_hdr)==1) { rec->state = AUTHENTICATING_STATE; } else { rec->state = INTERNAL_ERROR_STATE; } break; default: if(statuscode<400 && statuscode>=300) { LM_ERR("Redirection not implemented yet\n"); rec->state = INTERNAL_ERROR_STATE; } else { /* we got an error from the server */ rec->state = REGISTRAR_ERROR_STATE; rec->registration_timeout = now + rec->expires - timer_interval; } } lock_release(®_htable[cb_param->hash_index].lock); return; done: rec->state = INTERNAL_ERROR_STATE; rec->registration_timeout = now + rec->expires; lock_release(®_htable[cb_param->hash_index].lock); return; }
bool establish_http_proxy_passthru (struct http_proxy_info *p, socket_descriptor_t sd, /* already open to proxy */ const char *host, /* openvpn server remote */ const int port, /* openvpn server port */ struct buffer *lookahead, volatile int *signal_received) { struct gc_arena gc = gc_new (); char buf[512]; char buf2[128]; char get[80]; int status; int nparms; bool ret = false; bool processed = false; /* get user/pass if not previously given */ if (p->auth_method == HTTP_AUTH_BASIC || p->auth_method == HTTP_AUTH_DIGEST || p->auth_method == HTTP_AUTH_NTLM) get_user_pass_http (p, false); /* are we being called again after getting the digest server nonce in the previous transaction? */ if (p->auth_method == HTTP_AUTH_DIGEST && p->proxy_authenticate) { nparms = 1; status = 407; } else { /* format HTTP CONNECT message */ openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s", host, port, p->options.http_version); msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); /* send HTTP CONNECT message to proxy */ if (!send_line_crlf (sd, buf)) goto error; openvpn_snprintf(buf, sizeof(buf), "Host: %s", host); if (!send_line_crlf(sd, buf)) goto error; /* send User-Agent string if provided */ if (p->options.user_agent) { openvpn_snprintf (buf, sizeof(buf), "User-Agent: %s", p->options.user_agent); if (!send_line_crlf (sd, buf)) goto error; } /* auth specified? */ switch (p->auth_method) { case HTTP_AUTH_NONE: break; case HTTP_AUTH_BASIC: openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: Basic %s", username_password_as_base64 (p, &gc)); msg (D_PROXY, "Attempting Basic Proxy-Authorization"); dmsg (D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf); if (!send_line_crlf (sd, buf)) goto error; break; #if NTLM case HTTP_AUTH_NTLM: case HTTP_AUTH_NTLM2: /* keep-alive connection */ openvpn_snprintf (buf, sizeof(buf), "Proxy-Connection: Keep-Alive"); if (!send_line_crlf (sd, buf)) goto error; openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: NTLM %s", ntlm_phase_1 (p, &gc)); msg (D_PROXY, "Attempting NTLM Proxy-Authorization phase 1"); dmsg (D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf); if (!send_line_crlf (sd, buf)) goto error; break; #endif default: ASSERT (0); } /* send empty CR, LF */ if (!send_crlf (sd)) goto error; /* receive reply from proxy */ if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) goto error; /* remove trailing CR, LF */ chomp (buf); msg (D_PROXY, "HTTP proxy returned: '%s'", buf); /* parse return string */ nparms = sscanf (buf, "%*s %d", &status); } /* check for a "407 Proxy Authentication Required" response */ while (nparms >= 1 && status == 407) { msg (D_PROXY, "Proxy requires authentication"); if (p->auth_method == HTTP_AUTH_BASIC && !processed) { processed = true; } else if ((p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2) && !processed) /* check for NTLM */ { #if NTLM /* look for the phase 2 response */ while (true) { if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) goto error; chomp (buf); msg (D_PROXY, "HTTP proxy returned: '%s'", buf); openvpn_snprintf (get, sizeof get, "%%*s NTLM %%%ds", (int) sizeof (buf2) - 1); nparms = sscanf (buf, get, buf2); buf2[127] = 0; /* we only need the beginning - ensure it's null terminated. */ /* check for "Proxy-Authenticate: NTLM TlRM..." */ if (nparms == 1) { /* parse buf2 */ msg (D_PROXY, "auth string: '%s'", buf2); break; } } /* if we are here then auth string was got */ msg (D_PROXY, "Received NTLM Proxy-Authorization phase 2 response"); /* receive and discard everything else */ while (recv_line (sd, NULL, 0, 2, true, NULL, signal_received)) ; /* now send the phase 3 reply */ /* format HTTP CONNECT message */ openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s", host, port, p->options.http_version); msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); /* send HTTP CONNECT message to proxy */ if (!send_line_crlf (sd, buf)) goto error; /* keep-alive connection */ openvpn_snprintf (buf, sizeof(buf), "Proxy-Connection: Keep-Alive"); if (!send_line_crlf (sd, buf)) goto error; /* send HOST etc, */ openvpn_snprintf (buf, sizeof(buf), "Host: %s", host); msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); if (!send_line_crlf (sd, buf)) goto error; msg (D_PROXY, "Attempting NTLM Proxy-Authorization phase 3"); { const char *np3 = ntlm_phase_3 (p, buf2, &gc); if (!np3) { msg (D_PROXY, "NTLM Proxy-Authorization phase 3 failed: received corrupted data from proxy server"); goto error; } openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: NTLM %s", np3); } msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); if (!send_line_crlf (sd, buf)) goto error; /* ok so far... */ /* send empty CR, LF */ if (!send_crlf (sd)) goto error; /* receive reply from proxy */ if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) goto error; /* remove trailing CR, LF */ chomp (buf); msg (D_PROXY, "HTTP proxy returned: '%s'", buf); /* parse return string */ nparms = sscanf (buf, "%*s %d", &status); processed = true; #endif } #if PROXY_DIGEST_AUTH else if (p->auth_method == HTTP_AUTH_DIGEST && !processed) { char *pa = p->proxy_authenticate; const int method = p->auth_method; ASSERT(pa); if (method == HTTP_AUTH_DIGEST) { const char *http_method = "CONNECT"; const char *nonce_count = "00000001"; const char *qop = "auth"; const char *username = p->up.username; const char *password = p->up.password; char *opaque_kv = ""; char uri[128]; uint8_t cnonce_raw[8]; uint8_t *cnonce; HASHHEX session_key; HASHHEX response; const char *realm = get_pa_var("realm", pa, &gc); const char *nonce = get_pa_var("nonce", pa, &gc); const char *algor = get_pa_var("algorithm", pa, &gc); const char *opaque = get_pa_var("opaque", pa, &gc); /* generate a client nonce */ ASSERT(rand_bytes(cnonce_raw, sizeof(cnonce_raw))); cnonce = make_base64_string2(cnonce_raw, sizeof(cnonce_raw), &gc); /* build the digest response */ openvpn_snprintf (uri, sizeof(uri), "%s:%d", host, port); if (opaque) { const int len = strlen(opaque)+16; opaque_kv = gc_malloc(len, false, &gc); openvpn_snprintf (opaque_kv, len, ", opaque=\"%s\"", opaque); } DigestCalcHA1(algor, username, realm, password, nonce, (char *)cnonce, session_key); DigestCalcResponse(session_key, nonce, nonce_count, (char *)cnonce, qop, http_method, uri, NULL, response); /* format HTTP CONNECT message */ openvpn_snprintf (buf, sizeof(buf), "%s %s HTTP/%s", http_method, uri, p->options.http_version); msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); /* send HTTP CONNECT message to proxy */ if (!send_line_crlf (sd, buf)) goto error; /* send HOST etc, */ openvpn_snprintf (buf, sizeof(buf), "Host: %s", host); msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); if (!send_line_crlf (sd, buf)) goto error; /* send digest response */ openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", qop=%s, nc=%s, cnonce=\"%s\", response=\"%s\"%s", username, realm, nonce, uri, qop, nonce_count, cnonce, response, opaque_kv ); msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); if (!send_line_crlf (sd, buf)) goto error; if (!send_crlf (sd)) goto error; /* receive reply from proxy */ if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) goto error; /* remove trailing CR, LF */ chomp (buf); msg (D_PROXY, "HTTP proxy returned: '%s'", buf); /* parse return string */ nparms = sscanf (buf, "%*s %d", &status); processed = true; } else { msg (D_PROXY, "HTTP proxy: digest method not supported"); goto error; } } #endif else if (p->options.auth_retry) { /* figure out what kind of authentication the proxy needs */ char *pa = NULL; const int method = get_proxy_authenticate(sd, p->options.timeout, &pa, NULL, signal_received); if (method != HTTP_AUTH_NONE) { if (pa) msg (D_PROXY, "HTTP proxy authenticate '%s'", pa); if (p->options.auth_retry == PAR_NCT && method == HTTP_AUTH_BASIC) { msg (D_PROXY, "HTTP proxy: support for basic auth and other cleartext proxy auth methods is disabled"); goto error; } p->auth_method = method; store_proxy_authenticate(p, pa); ret = true; goto done; } else { msg (D_PROXY, "HTTP proxy: do not recognize the authentication method required by proxy"); free (pa); goto error; } } else { if (!processed) msg (D_PROXY, "HTTP proxy: no support for proxy authentication method"); goto error; } /* clear state */ if (p->options.auth_retry) clear_user_pass_http(); store_proxy_authenticate(p, NULL); } /* check return code, success = 200 */ if (nparms < 1 || status != 200) { msg (D_LINK_ERRORS, "HTTP proxy returned bad status"); #if 0 /* DEBUGGING -- show a multi-line HTTP error response */ dump_residual(sd, p->options.timeout, signal_received); #endif goto error; } /* SUCCESS */ /* receive line from proxy and discard */ if (!recv_line (sd, NULL, 0, p->options.timeout, true, NULL, signal_received)) goto error; /* * Toss out any extraneous chars, but don't throw away the * start of the OpenVPN data stream (put it in lookahead). */ while (recv_line (sd, NULL, 0, 2, false, lookahead, signal_received)) ; /* reset queried_creds so that we don't think that the next creds request is due to an auth error */ p->queried_creds = false; #if 0 if (lookahead && BLEN (lookahead)) msg (M_INFO, "HTTP PROXY: lookahead: %s", format_hex (BPTR (lookahead), BLEN (lookahead), 0)); #endif done: gc_free (&gc); return ret; error: /* on error, should we exit or restart? */ if (!*signal_received) *signal_received = (p->options.retry ? SIGUSR1 : SIGTERM); /* SOFT-SIGUSR1 -- HTTP proxy error */ gc_free (&gc); return ret; }
int run_reg_tm_cback(void *e_data, void *data, void *r_data) { struct sip_msg *msg; int statuscode = 0; unsigned int exp = 0; reg_record_t *rec = (reg_record_t*)e_data; struct hdr_field *c_ptr, *head_contact; struct uac_credential crd; contact_t *contact; struct authenticate_body *auth = NULL; static struct authenticate_nc_cnonce auth_nc_cnonce; HASHHEX response; str *new_hdr; struct reg_tm_cback_data *tm_cback_data = (struct reg_tm_cback_data*)data; struct cell *t; struct tmcb_params *ps; time_t now; reg_tm_cb_t *cb_param; cb_param = tm_cback_data->cb_param; if (rec!=cb_param->uac) { /* no action on current list elemnt */ return 0; /* continue list traversal */ } t = tm_cback_data->t; ps = tm_cback_data->ps; now = tm_cback_data->now; reg_print_record(rec); if (ps->rpl==FAKED_REPLY) memset(&rec->td.forced_to_su, 0, sizeof(union sockaddr_union)); else if (rec->td.forced_to_su.s.sa_family == AF_UNSPEC) rec->td.forced_to_su = t->uac[0].request.dst.to; statuscode = ps->code; switch(statuscode) { case 200: msg = ps->rpl; if(msg==FAKED_REPLY) { LM_ERR("FAKED_REPLY\n"); goto done; } if (parse_headers(msg, HDR_EOH_F, 0) == -1) { LM_ERR("failed to parse headers\n"); goto done; } if (msg->contact) { c_ptr = msg->contact; while(c_ptr) { if (c_ptr->type == HDR_CONTACT_T) { if (!c_ptr->parsed && (parse_contact(c_ptr)<0)) { LM_ERR("failed to parse Contact body\n"); goto done; } } c_ptr = c_ptr->next; } } else { LM_ERR("No contact header in received 200ok\n"); goto done; } head_contact = msg->contact; contact = ((contact_body_t*)msg->contact->parsed)->contacts; while (contact) { /* Check for binding */ if (contact->uri.len==rec->contact_uri.len && strncmp(contact->uri.s,rec->contact_uri.s,contact->uri.len)==0){ if (contact->expires && contact->expires->body.len) { if (str2int(&contact->expires->body, &exp)<0) { LM_ERR("Unable to extract expires from [%.*s]" " for binding [%.*s]\n", contact->expires->body.len, contact->expires->body.s, contact->uri.len, contact->uri.s); } } break; } /* get the next contact */ if (contact->next == NULL) { contact = NULL; c_ptr = head_contact->next; while(c_ptr) { if (c_ptr->type == HDR_CONTACT_T) { head_contact = c_ptr; contact = ((contact_body_t*)c_ptr->parsed)->contacts; break; } c_ptr = c_ptr->next; } } else { contact = contact->next; } } rec->state = REGISTERED_STATE; if (exp) rec->expires = exp; rec->registration_timeout = now + rec->expires - timer_interval; break; case WWW_AUTH_CODE: case PROXY_AUTH_CODE: msg = ps->rpl; if(msg==FAKED_REPLY) { LM_ERR("FAKED_REPLY\n"); goto done; } if (rec->auth_user.s==NULL || rec->auth_user.len==0 || rec->auth_password.s==NULL || rec->auth_password.len==0) { LM_ERR("Credentials not provisioned\n"); rec->state = WRONG_CREDENTIALS_STATE; rec->registration_timeout = 0; /* action successfuly completed on current list element */ return 1; /* exit list traversal */ } if (statuscode==WWW_AUTH_CODE) { if (0 == parse_www_authenticate_header(msg)) auth = get_www_authenticate(msg); } else if (statuscode==PROXY_AUTH_CODE) { if (0 == parse_proxy_authenticate_header(msg)) auth = get_proxy_authenticate(msg); } if (auth == NULL) { LM_ERR("Unable to extract authentication info\n"); goto done; } LM_DBG("flags=[%d] realm=[%.*s] domain=[%.*s] nonce=[%.*s]" " opaque=[%.*s] qop=[%.*s]\n", auth->flags, auth->realm.len, auth->realm.s, auth->domain.len, auth->domain.s, auth->nonce.len, auth->nonce.s, auth->opaque.len, auth->opaque.s, auth->qop.len, auth->qop.s); switch(rec->state) { case REGISTERING_STATE: break; case AUTHENTICATING_STATE: /* We already sent an authenticated REGISTER and we are still challanged! */ LM_WARN("Wrong credentials for [%.*s]\n", rec->td.rem_uri.len, rec->td.rem_uri.s); rec->state = WRONG_CREDENTIALS_STATE; rec->registration_timeout = 0; /* action successfuly completed on current list element */ return 1; /* exit list traversal */ default: LM_ERR("Unexpected [%d] notification cb in state [%d]\n", statuscode, rec->state); goto done; } /* perform authentication */ if (auth->realm.s && auth->realm.len) { crd.realm.s = auth->realm.s; crd.realm.len = auth->realm.len; } else { LM_ERR("No realm found\n"); goto done; } crd.user.s = rec->auth_user.s; crd.user.len = rec->auth_user.len; crd.passwd.s = rec->auth_password.s; crd.passwd.len = rec->auth_password.len; memset(&auth_nc_cnonce, 0, sizeof(struct authenticate_nc_cnonce)); uac_auth_api._do_uac_auth(®ister_method, &rec->td.rem_target, &crd, auth, &auth_nc_cnonce, response); new_hdr = uac_auth_api._build_authorization_hdr(statuscode, &rec->td.rem_target, &crd, auth, &auth_nc_cnonce, response); if (!new_hdr) { LM_ERR("failed to build authorization hdr\n"); goto done; } if(send_register(cb_param->hash_index, rec, new_hdr)==1) { rec->state = AUTHENTICATING_STATE; } else { rec->state = INTERNAL_ERROR_STATE; } pkg_free(new_hdr->s); new_hdr->s = NULL; new_hdr->len = 0; break; case 423: /* Interval Too Brief */ msg = ps->rpl; if(msg==FAKED_REPLY) { LM_ERR("FAKED_REPLY\n"); goto done; } if (0 == parse_min_expires(msg)) { rec->expires = (unsigned int)(long)msg->min_expires->parsed; if(send_register(cb_param->hash_index, rec, NULL)==1) rec->state = REGISTERING_STATE; else rec->state = INTERNAL_ERROR_STATE; } else { rec->state = REGISTRAR_ERROR_STATE; rec->registration_timeout = now + rec->expires - timer_interval; } break; case 408: /* Interval Too Brief */ rec->state = REGISTER_TIMEOUT_STATE; rec->registration_timeout = now + rec->expires - timer_interval; break; default: if(statuscode<400 && statuscode>=300) { LM_ERR("Redirection not implemented yet\n"); rec->state = INTERNAL_ERROR_STATE; } else { /* we got an error from the server */ rec->state = REGISTRAR_ERROR_STATE; rec->registration_timeout = now + rec->expires - timer_interval; } } /* action successfuly completed on current list element */ return 1; /* exit list traversal */ done: rec->state = INTERNAL_ERROR_STATE; rec->registration_timeout = now + rec->expires; return -1; /* exit list traversal */ }
int uac_auth( struct sip_msg *msg) { struct authenticate_body *auth = NULL; static struct authenticate_nc_cnonce auth_nc_cnonce; struct uac_credential *crd; int code, branch; struct sip_msg *rpl; struct cell *t; HASHHEX response; str *new_hdr; /* get transaction */ t = uac_tmb.t_gett(); if (t==T_UNDEFINED || t==T_NULL_CELL) { LM_CRIT("no current transaction found\n"); goto error; } /* get the selected branch */ branch = uac_tmb.t_get_picked(); if (branch<0) { LM_CRIT("no picked branch (%d)\n",branch); goto error; } rpl = t->uac[branch].reply; code = t->uac[branch].last_received; LM_DBG("picked reply is %p, code %d\n",rpl,code); if (rpl==0) { LM_CRIT("empty reply on picked branch\n"); goto error; } if (rpl==FAKED_REPLY) { LM_ERR("cannot process a FAKED reply\n"); goto error; } if (code==WWW_AUTH_CODE) { if (0 == parse_www_authenticate_header(rpl)) auth = get_www_authenticate(rpl); } else if (code==PROXY_AUTH_CODE) { if (0 == parse_proxy_authenticate_header(rpl)) auth = get_proxy_authenticate(rpl); } if (auth == NULL) { LM_ERR("Unable to extract authentication info\n"); goto error; } /* can we authenticate this realm? */ crd = 0; /* first look into AVP, if set */ if ( auth_realm_spec.type==PVT_AVP ) crd = get_avp_credential( msg, &auth->realm ); /* if not found, look into predefined credentials */ if (crd==0) crd = uac_auth_api._lookup_realm( &auth->realm ); /* found? */ if (crd==0) { LM_DBG("no credential for realm \"%.*s\"\n", auth->realm.len, auth->realm.s); goto error; } /* do authentication */ uac_auth_api._do_uac_auth( &msg->first_line.u.request.method, &t->uac[branch].uri, crd, auth, &auth_nc_cnonce, response); /* build the authorization header */ new_hdr = uac_auth_api._build_authorization_hdr( code, &t->uac[branch].uri, crd, auth, &auth_nc_cnonce, response); if (new_hdr==0) { LM_ERR("failed to build authorization hdr\n"); goto error; } /* so far, so good -> add the header and set the proper RURI */ if ( apply_urihdr_changes( msg, &t->uac[branch].uri, new_hdr)<0 ) { LM_ERR("failed to apply changes\n"); goto error; } /* increas the Cseq nr */ return 0; error: return -1; }