00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <ctype.h>
00031 #include <string.h>
00032
00033 #include "../../cmpapi.h"
00034 #include "../../dprint.h"
00035 #include "../../pvar.h"
00036 #include "../../data_lump.h"
00037 #include "../../mem/mem.h"
00038 #include "../tm/tm_load.h"
00039
00040 #include "auth.h"
00041 #include "auth_alg.h"
00042 #include "auth_hdr.h"
00043
00044
00045 extern struct tm_binds uac_tmb;
00046 extern pv_spec_t auth_username_spec;
00047 extern pv_spec_t auth_realm_spec;
00048 extern pv_spec_t auth_password_spec;
00049
00050
00051 static struct uac_credential *crd_list = 0;
00052
00053
00054 #define duplicate_str(_strd, _strs, _error) \
00055 do { \
00056 _strd.s = (char*)pkg_malloc(_strs.len); \
00057 if (_strd.s==0) \
00058 { \
00059 LM_ERR("no more pkg memory\n");\
00060 goto _error; \
00061 } \
00062 memcpy( _strd.s, _strs.s, _strs.len); \
00063 _strd.len = _strs.len; \
00064 }while(0)
00065
00066
00067 #define WWW_AUTH_CODE 401
00068 #define WWW_AUTH_HDR "WWW-Authenticate"
00069 #define WWW_AUTH_HDR_LEN (sizeof(WWW_AUTH_HDR)-1)
00070 #define PROXY_AUTH_CODE 407
00071 #define PROXY_AUTH_HDR "Proxy-Authenticate"
00072 #define PROXY_AUTH_HDR_LEN (sizeof(PROXY_AUTH_HDR)-1)
00073
00074 static str nc = {"00000001", 8};
00075 static str cnonce = {"o", 1};
00076
00077 int has_credentials(void)
00078 {
00079 return (crd_list!=0)?1:0;
00080 }
00081
00082 void free_credential(struct uac_credential *crd)
00083 {
00084 if (crd)
00085 {
00086 if (crd->realm.s)
00087 pkg_free(crd->realm.s);
00088 if (crd->user.s)
00089 pkg_free(crd->user.s);
00090 if (crd->passwd.s)
00091 pkg_free(crd->passwd.s);
00092 pkg_free(crd);
00093 }
00094 }
00095
00096
00097 int add_credential( unsigned int type, void *val)
00098 {
00099 struct uac_credential *crd;
00100 char *p;
00101 str foo;
00102
00103 p = (char*)val;
00104 crd = 0;
00105
00106 if (p==0 || *p==0)
00107 goto error;
00108
00109 crd = (struct uac_credential*)pkg_malloc(sizeof(struct uac_credential));
00110 if (crd==0)
00111 {
00112 LM_ERR("no more pkg mem\n");
00113 goto error;
00114 }
00115 memset( crd, 0, sizeof(struct uac_credential));
00116
00117
00118 while (*p && isspace((int)*p)) p++;
00119 foo.s = p;
00120 while (*p && *p!=':' && !isspace((int)*p)) p++;
00121 if (foo.s==p || *p==0)
00122
00123 goto parse_error;
00124 foo.len = p - foo.s;
00125
00126 duplicate_str( crd->user, foo, error);
00127
00128
00129 while (*p && isspace((int)*p)) p++;
00130 if (*p!=':')
00131 goto parse_error;
00132 p++;
00133 while (*p && isspace((int)*p)) p++;
00134 if (*p==0)
00135 goto parse_error;
00136
00137
00138 while (*p && isspace((int)*p)) p++;
00139 foo.s = p;
00140 while (*p && *p!=':' && !isspace((int)*p)) p++;
00141 if (foo.s==p || *p==0)
00142
00143 goto parse_error;
00144 foo.len = p - foo.s;
00145
00146 duplicate_str( crd->realm, foo, error);
00147
00148
00149 while (*p && isspace((int)*p)) p++;
00150 if (*p!=':')
00151 goto parse_error;
00152 p++;
00153 while (*p && isspace((int)*p)) p++;
00154 if (*p==0)
00155 goto parse_error;
00156
00157
00158 while (*p && isspace((int)*p)) p++;
00159 foo.s = p;
00160 while (*p && !isspace((int)*p)) p++;
00161 if (foo.s==p)
00162
00163 goto parse_error;
00164 foo.len = p - foo.s;
00165
00166 duplicate_str( crd->passwd, foo, error);
00167
00168
00169 while (*p && isspace((int)*p)) p++;
00170 if (*p!=0)
00171 goto parse_error;
00172
00173
00174 crd->next = crd_list;
00175 crd_list = crd;
00176
00177 pkg_free(val);
00178 return 0;
00179 parse_error:
00180 LM_ERR("parse error in <%s> "
00181 "around %ld\n", (char*)val, (long)(p-(char*)val));
00182 error:
00183 if (crd)
00184 free_credential(crd);
00185 return -1;
00186 }
00187
00188
00189 void destroy_credentials(void)
00190 {
00191 struct uac_credential *foo;
00192
00193 while (crd_list)
00194 {
00195 foo = crd_list;
00196 crd_list = crd_list->next;
00197 free_credential(foo);
00198 }
00199 crd_list = 0;
00200 }
00201
00202
00203 static inline struct hdr_field *get_autenticate_hdr(struct sip_msg *rpl,
00204 int rpl_code)
00205 {
00206 struct hdr_field *hdr;
00207 str hdr_name;
00208
00209
00210 if (rpl_code==WWW_AUTH_CODE)
00211 {
00212 hdr_name.s = WWW_AUTH_HDR;
00213 hdr_name.len = WWW_AUTH_HDR_LEN;
00214 } else if (rpl_code==PROXY_AUTH_CODE) {
00215 hdr_name.s = PROXY_AUTH_HDR;
00216 hdr_name.len = PROXY_AUTH_HDR_LEN;
00217 } else {
00218 LM_ERR("reply is not an "
00219 "auth request\n");
00220 goto error;
00221 }
00222
00223 LM_DBG("looking for header \"%.*s\"\n",
00224 hdr_name.len, hdr_name.s);
00225
00226
00227 if (parse_headers( rpl, HDR_EOH_F, 0)<0)
00228 {
00229 LM_ERR("failed to parse reply\n");
00230 goto error;
00231 }
00232 for( hdr=rpl->headers ; hdr ; hdr=hdr->next )
00233 {
00234 if ( hdr->type!=HDR_OTHER_T )
00235 continue;
00236 if (cmp_hdrname_str(&hdr->name, &hdr_name)==0)
00237 return hdr;
00238 }
00239
00240 LM_ERR("reply has no "
00241 "auth hdr (%.*s)\n", hdr_name.len, hdr_name.s);
00242 error:
00243 return 0;
00244 }
00245
00246
00247 static inline struct uac_credential *lookup_realm( str *realm)
00248 {
00249 struct uac_credential *crd;
00250
00251 for( crd=crd_list ; crd ; crd=crd->next )
00252 if (realm->len==crd->realm.len &&
00253 strncmp( realm->s, crd->realm.s, realm->len)==0 )
00254 return crd;
00255 return 0;
00256 }
00257
00258
00259 static inline struct uac_credential *get_avp_credential(struct sip_msg *msg,
00260 str *realm)
00261 {
00262 static struct uac_credential crd;
00263 pv_value_t pv_val;
00264
00265 if(pv_get_spec_value( msg, &auth_realm_spec, &pv_val)!=0
00266 || pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0)
00267 return 0;
00268
00269 crd.realm = pv_val.rs;
00270
00271 if (realm->len!=crd.realm.len ||
00272 strncmp( realm->s, crd.realm.s, realm->len)!=0 )
00273 return 0;
00274
00275
00276 if(pv_get_spec_value( msg, &auth_username_spec, &pv_val)!=0
00277 || pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0)
00278 return 0;
00279 crd.user = pv_val.rs;
00280
00281 if(pv_get_spec_value( msg, &auth_password_spec, &pv_val)!=0
00282 || pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0)
00283 return 0;
00284 crd.passwd = pv_val.rs;
00285
00286 return &crd;
00287 }
00288
00289
00290 static inline void do_uac_auth(struct sip_msg *req, str *uri,
00291 struct uac_credential *crd, struct authenticate_body *auth,
00292 HASHHEX response)
00293 {
00294 HASHHEX ha1;
00295 HASHHEX ha2;
00296
00297 if((auth->flags&QOP_AUTH) || (auth->flags&QOP_AUTH_INT))
00298 {
00299
00300 cnonce.s = int2str(core_hash(&auth->nonce, 0, 0),&cnonce.len);
00301
00302
00303 uac_calc_HA1( crd, auth, &cnonce, ha1);
00304 uac_calc_HA2( &req->first_line.u.request.method, uri,
00305 auth, 0, ha2 );
00306
00307 uac_calc_response( ha1, ha2, auth, &nc, &cnonce, response);
00308 auth->nc = &nc;
00309 auth->cnonce = &cnonce;
00310 } else {
00311
00312 uac_calc_HA1( crd, auth, 0, ha1);
00313 uac_calc_HA2( &req->first_line.u.request.method, uri,
00314 auth, 0, ha2 );
00315
00316 uac_calc_response( ha1, ha2, auth, 0, 0, response);
00317 }
00318 }
00319
00320
00321 static inline int apply_urihdr_changes( struct sip_msg *req,
00322 str *uri, str *hdr)
00323 {
00324 struct lump* anchor;
00325
00326
00327 if (req->new_uri.s)
00328 {
00329 pkg_free(req->new_uri.s);
00330 req->new_uri.len=0;
00331 }
00332 req->parsed_uri_ok=0;
00333 req->new_uri.s = (char*)pkg_malloc(uri->len+1);
00334 if (req->new_uri.s==0)
00335 {
00336 LM_ERR("no more pkg\n");
00337 goto error;
00338 }
00339 memcpy( req->new_uri.s, uri->s, uri->len);
00340 req->new_uri.s[uri->len]=0;
00341 req->new_uri.len=uri->len;
00342
00343
00344 if (parse_headers(req, HDR_EOH_F, 0) == -1)
00345 {
00346 LM_ERR("failed to parse message\n");
00347 goto error;
00348 }
00349
00350 anchor = anchor_lump(req, req->unparsed - req->buf, 0, 0);
00351 if (anchor==0)
00352 {
00353 LM_ERR("failed to get anchor\n");
00354 goto error;
00355 }
00356
00357 if (insert_new_lump_before(anchor, hdr->s, hdr->len, 0) == 0)
00358 {
00359 LM_ERR("faield to insert lump\n");
00360 goto error;
00361 }
00362
00363 return 0;
00364 error:
00365 pkg_free( hdr->s );
00366 return -1;
00367 }
00368
00369
00370
00371 int uac_auth( struct sip_msg *msg)
00372 {
00373 static struct authenticate_body auth;
00374 struct uac_credential *crd;
00375 int code, branch;
00376 struct sip_msg *rpl;
00377 struct cell *t;
00378 struct hdr_field *hdr;
00379 HASHHEX response;
00380 str *new_hdr;
00381
00382
00383 t = uac_tmb.t_gett();
00384 if (t==T_UNDEFINED || t==T_NULL_CELL)
00385 {
00386 LM_CRIT("no current transaction found\n");
00387 goto error;
00388 }
00389
00390
00391 branch = uac_tmb.t_get_picked();
00392 if (branch<0) {
00393 LM_CRIT("no picked branch (%d)\n",branch);
00394 goto error;
00395 }
00396
00397 rpl = t->uac[branch].reply;
00398 code = t->uac[branch].last_received;
00399 LM_DBG("picked reply is %p, code %d\n",rpl,code);
00400
00401 if (rpl==0)
00402 {
00403 LM_CRIT("empty reply on picked branch\n");
00404 goto error;
00405 }
00406 if (rpl==FAKED_REPLY)
00407 {
00408 LM_ERR("cannot process a FAKED reply\n");
00409 goto error;
00410 }
00411
00412 hdr = get_autenticate_hdr( rpl, code);
00413 if (hdr==0)
00414 {
00415 LM_ERR("failed to extract authenticate hdr\n");
00416 goto error;
00417 }
00418
00419 LM_DBG("header found; body=<%.*s>\n",
00420 hdr->body.len, hdr->body.s);
00421
00422 if (parse_authenticate_body( &hdr->body, &auth)<0)
00423 {
00424 LM_ERR("failed to parse auth hdr body\n");
00425 goto error;
00426 }
00427
00428
00429 crd = 0;
00430
00431 if ( auth_realm_spec.type==PVT_AVP )
00432 crd = get_avp_credential( msg, &auth.realm );
00433
00434 if (crd==0)
00435 crd = lookup_realm( &auth.realm );
00436
00437 if (crd==0)
00438 {
00439 LM_DBG("no credential for realm \"%.*s\"\n",
00440 auth.realm.len, auth.realm.s);
00441 goto error;
00442 }
00443
00444
00445 do_uac_auth( msg, &t->uac[branch].uri, crd, &auth, response);
00446
00447
00448 new_hdr = build_authorization_hdr( code, &t->uac[branch].uri,
00449 crd, &auth, response);
00450 if (new_hdr==0)
00451 {
00452 LM_ERR("failed to build authorization hdr\n");
00453 goto error;
00454 }
00455
00456
00457 if ( apply_urihdr_changes( msg, &t->uac[branch].uri, new_hdr)<0 )
00458 {
00459 LM_ERR("failed to apply changes\n");
00460 goto error;
00461 }
00462
00463
00464
00465
00466 return 0;
00467 error:
00468 return -1;
00469 }
00470
00471
00472