Index: modules/uac/auth.c
diff -Nau modules/uac/auth.c.orig modules/uac/auth.c
--- modules/uac/auth.c.orig	2010-01-18 12:32:26.152280000 +0100
+++ modules/uac/auth.c	2010-02-10 20:25:06.204228079 +0100
@@ -24,6 +24,7 @@
  * ---------
  *  2005-01-31  first version (ramona)
  *  2006-03-02  UAC authentication looks first in AVPs for credential (bogdan)
+ *  2010-01-18  UAC replaces proxy-auth entries with new credentials (msvb)
  */
 
 
@@ -375,14 +376,172 @@
 	HASHHEX response;
 	str *new_hdr;
 
+	/* pretransact */
+	int nret = 0;
+	pv_value_t pv_val;
+	str *newuri = 0;
+	struct uac_credential *tst = 0;
+	struct hdr_field *tmp_hdr = 0;
+	struct hdr_field *del_hdr = 0;
+
+
+	/* Goes something like this...                          */
+	/* HA1 = echo -n 'username:realm:password' | md5sum     */
+	/*       echo -n 'itsme:mydom.com:stupidpass' | md5sum  */
+	/* HA2 = echo -n 'message:uri' | md5sum                 */
+	/*       echo -n 'INVITE:sip:danc@ing.fool.es' | md5sum */
+	/* Response = echo -n 'HA1:nonce:HA2' | md5sum          */
 	/* get transaction */
 	t = uac_tmb.t_gett();
-	if (t==T_UNDEFINED || t==T_NULL_CELL)
-	{
-		LM_CRIT("no current transaction found\n");
-		goto error;
-	}
+	if (t==T_UNDEFINED || t==T_NULL_CELL) {
+		/* begin without any transaction */
+		/* set relevant structure variables */
+		crd = 0;
+		crd = pkg_malloc(sizeof(struct uac_credential));
+		if (!crd) {
+			LM_ERR("no more pkg memory\n");
+			goto error;
+		}
+
+		/* set the realm from existing UAC message */
+		tmp_hdr = msg->proxy_auth;
+		del_hdr = 0;
+		while (tmp_hdr) {
+			crd->realm.s = strchr(strstr(tmp_hdr->body.s, "realm="), '"') + 1;
+			crd->realm.len = strchr(crd->realm.s, '"') - crd->realm.s;
+			if(pv_get_spec_value(msg, &auth_realm_spec, &pv_val)==0 \
+				&& pv_val.rs.len>0) /* ensure realm is the desired one */
+				if (strncmp(crd->realm.s, pv_val.rs.s, crd->realm.len)==0)
+					del_hdr = tmp_hdr;
+			tmp_hdr = tmp_hdr->sibling;
+		}
+		if (del_hdr)
+			crd->realm = pv_val.rs;	/* success */
+		else
+			nret++;					/* failure */
+
+		/* set username from new AVP proxy values */
+		if(pv_get_spec_value(msg, &auth_username_spec, &pv_val)!=0 \
+			|| pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0)
+			nret++; /* signal failure with nonzero value */
+		else
+			crd->user = pv_val.rs;
+
+		/* set password from new AVP proxy values */
+		if(pv_get_spec_value(msg, &auth_password_spec, &pv_val)!=0 \
+			|| pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0)
+			nret++; /* signal failure with nonzero value */
+		else
+			crd->passwd = pv_val.rs;
+
+		if (nret) { /* if not found, look into predefined credentials */
+			tst = lookup_realm(&crd->realm);
+
+			if (tst==0) { /* found? */
+				LM_DBG("no credential for realm \"%.*s\"\n", \
+					crd->realm.len, crd->realm.s);
+				pkg_free(crd);
+				goto error;
+			}
+
+			crd = tst; /* use predefined credentials */
+			/* set the realm from existing UAC message */
+			tmp_hdr = msg->proxy_auth;
+			del_hdr = 0;
+			while (tmp_hdr) {
+				if(pv_get_spec_value(msg, &auth_realm_spec, &pv_val)==0 \
+					&& pv_val.rs.len>0) /* ensure realm is the desired one */
+					if (strncmp(crd->realm.s, pv_val.rs.s, crd->realm.len)==0)
+						del_hdr = tmp_hdr;
+				tmp_hdr = tmp_hdr->sibling;
+			}
+			if (del_hdr == 0) { /* proxy-auth header matching realm not found */
+				LM_DBG("no credential for realm \"%.*s\"\n", \
+					crd->realm.len, crd->realm.s);
+				pkg_free(crd);
+				goto error;
+			}
+		}
+
+		/* set the uri from existing UAC message */
+		newuri = pkg_malloc(sizeof(str));
+		if (!newuri) {
+			LM_ERR("no more pkg memory\n");
+			goto error;
+		}
+		newuri->s = pkg_malloc(msg->new_uri.len);
+		if (!newuri->s) {
+			LM_ERR("no more pkg memory\n");
+			pkg_free(newuri);
+			goto error;
+		}
+		newuri->len = msg->new_uri.len;
+		strncpy(newuri->s, msg->new_uri.s, msg->new_uri.len);
+		if (!newuri->s) {
+			LM_DBG("failed to retrieve URI from UAC message\n");
+			pkg_free(newuri->s);
+			pkg_free(newuri);
+			goto error;
+		}
+
+		/* set the nonce from existing UAC message */
+		tmp_hdr = msg->proxy_auth;
+		auth.nonce.len = 0;
+		auth.nonce.s = 0;
+		while (tmp_hdr) {
+			if(pv_get_spec_value(msg, &auth_realm_spec, &pv_val)==0 \
+				&& pv_val.rs.len>0) /* ensure realm is the desired one */
+				if (strncmp(crd->realm.s, pv_val.rs.s, crd->realm.len)==0) {
+					auth.nonce.s = strchr(strstr(tmp_hdr->body.s, "nonce="), '"') + 1;
+					auth.nonce.len = strchr(auth.nonce.s, '"') - auth.nonce.s;
+				}
+			tmp_hdr = tmp_hdr->sibling;
+		}
+		if (auth.nonce.s == 0) {
+			LM_DBG("failed to retrieve nonce from UAC message\n");
+			pkg_free(crd);
+			goto error;
+		}
+
+		/* do authentication */
+		do_uac_auth(msg, newuri, crd, &auth, response);
+		if (response==0) {
+			LM_ERR("failed to calculate challenge response\n");
+			pkg_free(crd);
+			goto error;
+		}
+
+		/* build the authorization header */
+		new_hdr = build_authorization_hdr(407, newuri, crd, &auth, response);
+		if (new_hdr==0) {
+			LM_ERR("failed to build authorization hdr\n");
+			pkg_free(crd);
+			goto error;
+		}
+
+		/* remove the old proxy-auth header and relink message index    */
+		/* before updating the authorization credentials of the message */
+		if (del_hdr) { /* updated a record and must remove the old one  */
+			if (del_lump(msg, del_hdr->name.s - msg->buf, del_hdr->len, 0)==0) {
+				LM_ERR("can't remove credentials\n");
+				pkg_free(crd);
+				goto error;
+			}
+		}
+
+		/* so far, so good -> add the header and set the proper RURI */
+		if (apply_urihdr_changes(msg, newuri, new_hdr)<0)
+		{
+			LM_ERR("failed to apply changes\n");
+			pkg_free(crd);
+			goto error;
+		}
+
+		pkg_free(crd); /* finished calculating new response string, success */
+		return 0;
+	} /* if (t==T_UNDEFINED || t==T_NULL_CELL) */
 
+	/* begin with transaction reply */
 	/* get the selected branch */
 	branch = uac_tmb.t_get_picked();
 	if (branch<0) {
Index: modules/uac/uac.c
diff -Nau modules/uac/uac.c.orig modules/uac/uac.c
--- modules/uac/uac.c.orig	2010-01-18 12:32:26.159078000 +0100
+++ modules/uac/uac.c	2010-02-10 20:25:06.206731656 +0100
@@ -29,6 +29,7 @@
  *  2006-03-03  the RR parameter is encrypted via XOR with a password
  *              (bogdan)
  *  2009-08-22  TO header replacement added (bogdan)
+ *  2010-01-18  UAC is able to construct credentials from request (msvb)
 
  */
 
@@ -106,7 +107,7 @@
 			REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE },
 	{"uac_auth",          (cmd_function)w_uac_auth,       0,
 			0, 0,
-			FAILURE_ROUTE },
+			REQUEST_ROUTE|FAILURE_ROUTE },
 	{0,0,0,0,0,0}
 };
 
