Wed, 10 Feb 2010 21:25:01 +0100
Extend uac_auth() of the UAC module to workaround CSEQ problems.
This logic is meant to complement that of changeset 17, which
added rich authentication credentials to the gw table and its
associated logic in the LCR module.
1 Index: modules/uac/auth.c
2 diff -Nau modules/uac/auth.c.orig modules/uac/auth.c
3 --- modules/uac/auth.c.orig 2010-01-18 12:32:26.152280000 +0100
4 +++ modules/uac/auth.c 2010-02-10 20:25:06.204228079 +0100
5 @@ -24,6 +24,7 @@
6 * ---------
7 * 2005-01-31 first version (ramona)
8 * 2006-03-02 UAC authentication looks first in AVPs for credential (bogdan)
9 + * 2010-01-18 UAC replaces proxy-auth entries with new credentials (msvb)
10 */
13 @@ -375,14 +376,172 @@
14 HASHHEX response;
15 str *new_hdr;
17 + /* pretransact */
18 + int nret = 0;
19 + pv_value_t pv_val;
20 + str *newuri = 0;
21 + struct uac_credential *tst = 0;
22 + struct hdr_field *tmp_hdr = 0;
23 + struct hdr_field *del_hdr = 0;
24 +
25 +
26 + /* Goes something like this... */
27 + /* HA1 = echo -n 'username:realm:password' | md5sum */
28 + /* echo -n 'itsme:mydom.com:stupidpass' | md5sum */
29 + /* HA2 = echo -n 'message:uri' | md5sum */
30 + /* echo -n 'INVITE:sip:danc@ing.fool.es' | md5sum */
31 + /* Response = echo -n 'HA1:nonce:HA2' | md5sum */
32 /* get transaction */
33 t = uac_tmb.t_gett();
34 - if (t==T_UNDEFINED || t==T_NULL_CELL)
35 - {
36 - LM_CRIT("no current transaction found\n");
37 - goto error;
38 - }
39 + if (t==T_UNDEFINED || t==T_NULL_CELL) {
40 + /* begin without any transaction */
41 + /* set relevant structure variables */
42 + crd = 0;
43 + crd = pkg_malloc(sizeof(struct uac_credential));
44 + if (!crd) {
45 + LM_ERR("no more pkg memory\n");
46 + goto error;
47 + }
48 +
49 + /* set the realm from existing UAC message */
50 + tmp_hdr = msg->proxy_auth;
51 + del_hdr = 0;
52 + while (tmp_hdr) {
53 + crd->realm.s = strchr(strstr(tmp_hdr->body.s, "realm="), '"') + 1;
54 + crd->realm.len = strchr(crd->realm.s, '"') - crd->realm.s;
55 + if(pv_get_spec_value(msg, &auth_realm_spec, &pv_val)==0 \
56 + && pv_val.rs.len>0) /* ensure realm is the desired one */
57 + if (strncmp(crd->realm.s, pv_val.rs.s, crd->realm.len)==0)
58 + del_hdr = tmp_hdr;
59 + tmp_hdr = tmp_hdr->sibling;
60 + }
61 + if (del_hdr)
62 + crd->realm = pv_val.rs; /* success */
63 + else
64 + nret++; /* failure */
65 +
66 + /* set username from new AVP proxy values */
67 + if(pv_get_spec_value(msg, &auth_username_spec, &pv_val)!=0 \
68 + || pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0)
69 + nret++; /* signal failure with nonzero value */
70 + else
71 + crd->user = pv_val.rs;
72 +
73 + /* set password from new AVP proxy values */
74 + if(pv_get_spec_value(msg, &auth_password_spec, &pv_val)!=0 \
75 + || pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0)
76 + nret++; /* signal failure with nonzero value */
77 + else
78 + crd->passwd = pv_val.rs;
79 +
80 + if (nret) { /* if not found, look into predefined credentials */
81 + tst = lookup_realm(&crd->realm);
82 +
83 + if (tst==0) { /* found? */
84 + LM_DBG("no credential for realm \"%.*s\"\n", \
85 + crd->realm.len, crd->realm.s);
86 + pkg_free(crd);
87 + goto error;
88 + }
89 +
90 + crd = tst; /* use predefined credentials */
91 + /* set the realm from existing UAC message */
92 + tmp_hdr = msg->proxy_auth;
93 + del_hdr = 0;
94 + while (tmp_hdr) {
95 + if(pv_get_spec_value(msg, &auth_realm_spec, &pv_val)==0 \
96 + && pv_val.rs.len>0) /* ensure realm is the desired one */
97 + if (strncmp(crd->realm.s, pv_val.rs.s, crd->realm.len)==0)
98 + del_hdr = tmp_hdr;
99 + tmp_hdr = tmp_hdr->sibling;
100 + }
101 + if (del_hdr == 0) { /* proxy-auth header matching realm not found */
102 + LM_DBG("no credential for realm \"%.*s\"\n", \
103 + crd->realm.len, crd->realm.s);
104 + pkg_free(crd);
105 + goto error;
106 + }
107 + }
108 +
109 + /* set the uri from existing UAC message */
110 + newuri = pkg_malloc(sizeof(str));
111 + if (!newuri) {
112 + LM_ERR("no more pkg memory\n");
113 + goto error;
114 + }
115 + newuri->s = pkg_malloc(msg->new_uri.len);
116 + if (!newuri->s) {
117 + LM_ERR("no more pkg memory\n");
118 + pkg_free(newuri);
119 + goto error;
120 + }
121 + newuri->len = msg->new_uri.len;
122 + strncpy(newuri->s, msg->new_uri.s, msg->new_uri.len);
123 + if (!newuri->s) {
124 + LM_DBG("failed to retrieve URI from UAC message\n");
125 + pkg_free(newuri->s);
126 + pkg_free(newuri);
127 + goto error;
128 + }
129 +
130 + /* set the nonce from existing UAC message */
131 + tmp_hdr = msg->proxy_auth;
132 + auth.nonce.len = 0;
133 + auth.nonce.s = 0;
134 + while (tmp_hdr) {
135 + if(pv_get_spec_value(msg, &auth_realm_spec, &pv_val)==0 \
136 + && pv_val.rs.len>0) /* ensure realm is the desired one */
137 + if (strncmp(crd->realm.s, pv_val.rs.s, crd->realm.len)==0) {
138 + auth.nonce.s = strchr(strstr(tmp_hdr->body.s, "nonce="), '"') + 1;
139 + auth.nonce.len = strchr(auth.nonce.s, '"') - auth.nonce.s;
140 + }
141 + tmp_hdr = tmp_hdr->sibling;
142 + }
143 + if (auth.nonce.s == 0) {
144 + LM_DBG("failed to retrieve nonce from UAC message\n");
145 + pkg_free(crd);
146 + goto error;
147 + }
148 +
149 + /* do authentication */
150 + do_uac_auth(msg, newuri, crd, &auth, response);
151 + if (response==0) {
152 + LM_ERR("failed to calculate challenge response\n");
153 + pkg_free(crd);
154 + goto error;
155 + }
156 +
157 + /* build the authorization header */
158 + new_hdr = build_authorization_hdr(407, newuri, crd, &auth, response);
159 + if (new_hdr==0) {
160 + LM_ERR("failed to build authorization hdr\n");
161 + pkg_free(crd);
162 + goto error;
163 + }
164 +
165 + /* remove the old proxy-auth header and relink message index */
166 + /* before updating the authorization credentials of the message */
167 + if (del_hdr) { /* updated a record and must remove the old one */
168 + if (del_lump(msg, del_hdr->name.s - msg->buf, del_hdr->len, 0)==0) {
169 + LM_ERR("can't remove credentials\n");
170 + pkg_free(crd);
171 + goto error;
172 + }
173 + }
174 +
175 + /* so far, so good -> add the header and set the proper RURI */
176 + if (apply_urihdr_changes(msg, newuri, new_hdr)<0)
177 + {
178 + LM_ERR("failed to apply changes\n");
179 + pkg_free(crd);
180 + goto error;
181 + }
182 +
183 + pkg_free(crd); /* finished calculating new response string, success */
184 + return 0;
185 + } /* if (t==T_UNDEFINED || t==T_NULL_CELL) */
187 + /* begin with transaction reply */
188 /* get the selected branch */
189 branch = uac_tmb.t_get_picked();
190 if (branch<0) {
191 Index: modules/uac/uac.c
192 diff -Nau modules/uac/uac.c.orig modules/uac/uac.c
193 --- modules/uac/uac.c.orig 2010-01-18 12:32:26.159078000 +0100
194 +++ modules/uac/uac.c 2010-02-10 20:25:06.206731656 +0100
195 @@ -29,6 +29,7 @@
196 * 2006-03-03 the RR parameter is encrypted via XOR with a password
197 * (bogdan)
198 * 2009-08-22 TO header replacement added (bogdan)
199 + * 2010-01-18 UAC is able to construct credentials from request (msvb)
201 */
203 @@ -106,7 +107,7 @@
204 REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE },
205 {"uac_auth", (cmd_function)w_uac_auth, 0,
206 0, 0,
207 - FAILURE_ROUTE },
208 + REQUEST_ROUTE|FAILURE_ROUTE },
209 {0,0,0,0,0,0}
210 };