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
00031
00032
00033
00034
00035
00036
00037
00038 #include <stdio.h>
00039 #include <stdlib.h>
00040 #include <string.h>
00041 #include "../../ut.h"
00042 #include "../../str.h"
00043 #include "../../db/db.h"
00044 #include "../../dprint.h"
00045 #include "../../parser/digest/digest.h"
00046 #include "../../parser/hf.h"
00047 #include "../../parser/parser_f.h"
00048 #include "../../usr_avp.h"
00049 #include "../../mem/mem.h"
00050 #include "../../config.h"
00051 #include "../../id.h"
00052 #include "../auth/api.h"
00053 #include "authdb_mod.h"
00054
00055
00056 #define IS_NULL(f) ((f).flags & DB_NULL)
00057
00058 static inline int get_ha1(struct username* username, str* did, str* realm,
00059 authdb_table_info_t *table_info, char* ha1, db_res_t** res, db_rec_t** row)
00060 {
00061 str result;
00062 db_cmd_t *q = NULL;
00063
00064 if (calc_ha1) {
00065 q = table_info->query_password;
00066 DBG("querying plain password\n");
00067 } else {
00068 if (username->domain.len) {
00069 q = table_info->query_pass2;
00070 DBG("querying ha1b\n");
00071 } else {
00072 q = table_info->query_pass;
00073 DBG("querying ha1\n");
00074 }
00075 }
00076
00077 q->match[0].v.lstr = username->user;
00078 q->match[1].v.lstr = *realm;
00079
00080 if (use_did) q->match[2].v.lstr = *did;
00081
00082 if (db_exec(res, q) < 0 ) {
00083 ERR("Error while querying database\n");
00084 return -1;
00085 }
00086
00087 if (*res) *row = db_first(*res);
00088 else *row = NULL;
00089 while (*row) {
00090 if (IS_NULL((*row)->fld[0]) || IS_NULL((*row)->fld[1])) {
00091 LOG(L_ERR, "auth_db:get_ha1: Credentials for '%.*s'@'%.*s' contain NULL value, skipping\n",
00092 username->user.len, ZSW(username->user.s), realm->len, ZSW(realm->s));
00093 } else {
00094 if ((*row)->fld[1].v.int4 & DB_DISABLED) {
00095
00096 } else {
00097 if ((*row)->fld[1].v.int4 & DB_LOAD_SER) {
00098
00099 break;
00100 }
00101 }
00102 }
00103 *row = db_next(*res);
00104 }
00105
00106 if (!*row) {
00107 DBG("auth_db:get_ha1: Credentials for '%.*s'@'%.*s' not found\n",
00108 username->user.len, ZSW(username->user.s), realm->len, ZSW(realm->s));
00109 return 1;
00110 }
00111
00112 result.s = (*row)->fld[0].v.cstr;
00113 result.len = strlen(result.s);
00114
00115 if (calc_ha1) {
00116
00117
00118 auth_api.calc_HA1(HA_MD5, &username->whole, realm, &result, 0, 0, ha1);
00119 DBG("auth_db:get_ha1: HA1 string calculated: %s\n", ha1);
00120 } else {
00121 memcpy(ha1, result.s, result.len);
00122 ha1[result.len] = '\0';
00123 }
00124
00125 return 0;
00126 }
00127
00128
00129
00130
00131
00132 static inline int check_response(dig_cred_t* cred, str* method, char* ha1)
00133 {
00134 HASHHEX resp, hent;
00135
00136
00137
00138
00139
00140 if (cred->response.len != 32) {
00141 DBG("auth_db:check_response: Receive response len != 32\n");
00142 return 1;
00143 }
00144
00145
00146
00147
00148
00149 auth_api.calc_response(ha1, &(cred->nonce),
00150 &(cred->nc), &(cred->cnonce),
00151 &(cred->qop.qop_str), cred->qop.qop_parsed == QOP_AUTHINT,
00152 method, &(cred->uri), hent, resp);
00153
00154 DBG("auth_db:check_response: Our result = \'%s\'\n", resp);
00155
00156
00157
00158
00159
00160 if (!memcmp(resp, cred->response.s, 32)) {
00161 DBG("auth_db:check_response: Authorization is OK\n");
00162 return 0;
00163 } else {
00164 DBG("auth_db:check_response: Authorization failed\n");
00165 return 2;
00166 }
00167 }
00168
00169
00170
00171
00172
00173 static int generate_avps(db_res_t* result, db_rec_t *row)
00174 {
00175 int i;
00176 int_str iname, ivalue;
00177 str value;
00178 char buf[32];
00179
00180 for (i = 2; i < credentials_n + 2; i++) {
00181 value = row->fld[i].v.lstr;
00182
00183 if (IS_NULL(row->fld[i]))
00184 continue;
00185
00186 switch (row->fld[i].type) {
00187 case DB_STR:
00188 value = row->fld[i].v.lstr;
00189 break;
00190
00191 case DB_INT:
00192 value.len = sprintf(buf, "%d", row->fld[i].v.int4);
00193 value.s = buf;
00194 break;
00195
00196 default:
00197 abort();
00198 break;
00199 }
00200
00201 if (value.s == NULL)
00202 continue;
00203
00204 iname.s = credentials[i - 2];
00205 ivalue.s = value;
00206
00207 if (add_avp(AVP_NAME_STR | AVP_VAL_STR | AVP_CLASS_USER, iname, ivalue) < 0) {
00208 LOG(L_ERR, "auth_db:generate_avps: Error while creating AVPs\n");
00209 return -1;
00210 }
00211
00212 DBG("auth_db:generate_avps: set string AVP \'%.*s = %.*s\'\n",
00213 iname.s.len, ZSW(iname.s.s), value.len, ZSW(value.s));
00214 }
00215
00216 return 0;
00217 }
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228 static inline int check_all_ha1(struct sip_msg* msg, struct hdr_field* hdr,
00229 dig_cred_t* dig, str* method, str* did, str* realm,
00230 authdb_table_info_t *table_info, db_res_t** res)
00231 {
00232 char ha1[256];
00233 db_rec_t *row;
00234 str result;
00235 db_cmd_t *q;
00236
00237 if (calc_ha1) {
00238 q = table_info->query_password;
00239 DBG("querying plain password\n");
00240 }
00241 else {
00242 if (dig->username.domain.len) {
00243 q = table_info->query_pass2;
00244 DBG("querying ha1b\n");
00245 }
00246 else {
00247 q = table_info->query_pass;
00248 DBG("querying ha1\n");
00249 }
00250 }
00251
00252 q->match[0].v.lstr = dig->username.user;
00253 if (dig->username.domain.len)
00254 q->match[1].v.lstr = dig->username.domain;
00255 else
00256 q->match[1].v.lstr = *realm;
00257
00258 if (use_did) q->match[2].v.lstr = *did;
00259
00260 if (db_exec(res, q) < 0 ) {
00261 ERR("Error while querying database\n");
00262 }
00263
00264 if (*res) row = db_first(*res);
00265 else row = NULL;
00266 while (row) {
00267 if (IS_NULL(row->fld[0]) || IS_NULL(row->fld[1])) {
00268 LOG(L_ERR, "auth_db:check_all_ha1: Credentials for '%.*s'@'%.*s' contain NULL value, skipping\n",
00269 dig->username.user.len, ZSW(dig->username.user.s), realm->len, ZSW(realm->s));
00270 }
00271 else {
00272 if (row->fld[1].v.int4 & DB_DISABLED) {
00273
00274 }
00275 else {
00276 if (row->fld[1].v.int4 & DB_LOAD_SER) {
00277 result.s = row->fld[0].v.cstr;
00278 result.len = strlen(result.s);
00279 if (calc_ha1) {
00280
00281
00282 auth_api.calc_HA1(HA_MD5, &(dig->username.whole), realm, &result, 0, 0, ha1);
00283 DBG("auth_db:check_all_ha1: HA1 string calculated: %s\n", ha1);
00284 } else {
00285 memcpy(ha1, result.s, result.len);
00286 ha1[result.len] = '\0';
00287 }
00288
00289 if (!check_response(dig, method, ha1)) {
00290 if (auth_api.post_auth(msg, hdr) == AUTHENTICATED) {
00291 generate_avps(*res, row);
00292 return 0;
00293 }
00294 }
00295 }
00296 }
00297 }
00298 row = db_next(*res);
00299 }
00300
00301 if (!row) {
00302 DBG("auth_db:check_all_ha1: Credentials for '%.*s'@'%.*s' not found",
00303 dig->username.user.len, ZSW(dig->username.user.s), realm->len, ZSW(realm->s));
00304 }
00305 return 1;
00306
00307
00308 }
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319 static inline int authenticate(struct sip_msg* msg, str* realm, authdb_table_info_t *table, hdr_types_t hftype)
00320 {
00321 char ha1[256];
00322 int res, ret;
00323 db_rec_t *row;
00324 struct hdr_field* h;
00325 auth_body_t* cred;
00326 db_res_t* result;
00327 str did;
00328
00329 cred = 0;
00330 result = 0;
00331 ret = -1;
00332
00333 switch(auth_api.pre_auth(msg, realm, hftype, &h, NULL)) {
00334 case ERROR:
00335 case BAD_CREDENTIALS:
00336 ret = -3;
00337 goto end;
00338 case CREATE_CHALLENGE:
00339 ERR("auth_db:authenticate: CREATE_CHALLENGE is not a valid state\n");
00340 ret = -2;
00341 goto end;
00342 case DO_RESYNCHRONIZATION:
00343 ERR("auth_db:authenticate: DO_RESYNCHRONIZATION is not a valid state\n");
00344 ret = -2;
00345 goto end;
00346
00347 case NOT_AUTHENTICATED:
00348 ret = -1;
00349 goto end;
00350
00351 case DO_AUTHENTICATION:
00352 break;
00353
00354 case AUTHENTICATED:
00355 ret = 1;
00356 goto end;
00357 }
00358
00359 cred = (auth_body_t*)h->parsed;
00360
00361 if (use_did) {
00362 if (msg->REQ_METHOD == METHOD_REGISTER) {
00363 ret = get_to_did(&did, msg);
00364 } else {
00365 ret = get_from_did(&did, msg);
00366 }
00367 if (ret == 0) {
00368 did.s = DEFAULT_DID;
00369 did.len = sizeof(DEFAULT_DID) - 1;
00370 }
00371 } else {
00372 did.len = 0;
00373 did.s = 0;
00374 }
00375
00376
00377 if (check_all) {
00378 res = check_all_ha1(msg, h, &(cred->digest), &msg->first_line.u.request.method, &did, realm, table, &result);
00379 if (res < 0) {
00380 ret = -2;
00381 goto end;
00382 }
00383 else if (res > 0) {
00384 ret = -1;
00385 goto end;
00386 }
00387 else {
00388 ret = 1;
00389 goto end;
00390 }
00391 } else {
00392 res = get_ha1(&cred->digest.username, &did, realm, table, ha1, &result, &row);
00393 if (res < 0) {
00394 ret = -2;
00395 goto end;
00396 }
00397 if (res > 0) {
00398
00399 ret = -1;
00400 goto end;
00401 }
00402 }
00403
00404
00405 if (!check_response(&(cred->digest), &msg->first_line.u.request.method, ha1)) {
00406 switch(auth_api.post_auth(msg, h)) {
00407 case ERROR:
00408 case BAD_CREDENTIALS:
00409 ret = -2;
00410 break;
00411
00412 case NOT_AUTHENTICATED:
00413 ret = -1;
00414 break;
00415
00416 case AUTHENTICATED:
00417 generate_avps(result, row);
00418 ret = 1;
00419 break;
00420
00421 default:
00422 ret = -1;
00423 break;
00424 }
00425 } else {
00426 ret = -1;
00427 }
00428
00429 end:
00430 if (result) db_res_free(result);
00431 if (ret < 0) {
00432 if (auth_api.build_challenge(msg, (cred ? cred->stale : 0), realm, NULL, NULL, hftype) < 0) {
00433 ERR("Error while creating challenge\n");
00434 ret = -2;
00435 }
00436 }
00437 return ret;
00438 }
00439
00440
00441
00442
00443
00444 int proxy_authenticate(struct sip_msg* msg, char* p1, char* p2)
00445 {
00446 str realm;
00447
00448 if (get_str_fparam(&realm, msg, (fparam_t*)p1) < 0) {
00449 ERR("Cannot obtain digest realm from parameter '%s'\n", ((fparam_t*)p1)->orig);
00450 return -1;
00451 }
00452
00453 return authenticate(msg, &realm, (authdb_table_info_t*)p2, HDR_PROXYAUTH_T);
00454 }
00455
00456
00457
00458
00459
00460 int www_authenticate(struct sip_msg* msg, char* p1, char* p2)
00461 {
00462 str realm;
00463
00464 if (get_str_fparam(&realm, msg, (fparam_t*)p1) < 0) {
00465 ERR("Cannot obtain digest realm from parameter '%s'\n", ((fparam_t*)p1)->orig);
00466 return -1;
00467 }
00468
00469 return authenticate(msg, &realm, (authdb_table_info_t*)p2, HDR_AUTHORIZATION_T);
00470 }