authorize.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. /*
  2. * $Id$
  3. *
  4. * Digest Authentication - Database support
  5. *
  6. * Copyright (C) 2001-2003 FhG Fokus
  7. *
  8. * This file is part of Kamailio, a free SIP server.
  9. *
  10. * Kamailio is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version
  14. *
  15. * Kamailio is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  23. *
  24. * history:
  25. * ---------
  26. * 2003-02-28 scratchpad compatibility abandoned
  27. * 2003-01-27 next baby-step to removing ZT - PRESERVE_ZT (jiri)
  28. * 2004-06-06 updated to the new DB api, added auth_db_{init,bind,close,ver}
  29. * (andrei)
  30. * 2005-05-31 general definition of AVPs in credentials now accepted - ID AVP,
  31. * STRING AVP, AVP aliases (bogdan)
  32. * 2006-03-01 pseudo variables support for domain name (bogdan)
  33. */
  34. #include <string.h>
  35. #include "../../ut.h"
  36. #include "../../str.h"
  37. #include "../../lib/srdb1/db.h"
  38. #include "../../lib/srdb1/db_ut.h"
  39. #include "../../dprint.h"
  40. #include "../../parser/digest/digest.h"
  41. #include "../../parser/hf.h"
  42. #include "../../parser/parser_f.h"
  43. #include "../../parser/parse_from.h"
  44. #include "../../parser/parse_to.h"
  45. #include "../../parser/parse_uri.h"
  46. #include "../../usr_avp.h"
  47. #include "../../mod_fix.h"
  48. #include "../../mem/mem.h"
  49. #include "api.h"
  50. #include "authdb_mod.h"
  51. int fetch_credentials(sip_msg_t *msg, str *user, str* domain, str *table)
  52. {
  53. pv_elem_t *cred;
  54. db_key_t keys[2];
  55. db_val_t vals[2];
  56. db_key_t *col;
  57. db1_res_t *res = NULL;
  58. int n, nc;
  59. col = pkg_malloc(sizeof(*col) * (credentials_n + 1));
  60. if (col == NULL) {
  61. LM_ERR("no more pkg memory\n");
  62. return -1;
  63. }
  64. keys[0] = &user_column;
  65. keys[1] = &domain_column;
  66. for (n = 0, cred=credentials; cred ; n++, cred=cred->next) {
  67. col[n] = &cred->text;
  68. }
  69. VAL_TYPE(vals) = VAL_TYPE(vals + 1) = DB1_STR;
  70. VAL_NULL(vals) = VAL_NULL(vals + 1) = 0;
  71. n = 1;
  72. VAL_STR(vals) = *user;
  73. if (domain && domain->len) {
  74. VAL_STR(vals + 1) = *domain;
  75. n = 2;
  76. }
  77. nc = credentials_n;
  78. if (auth_dbf.use_table(auth_db_handle, table) < 0) {
  79. LM_ERR("failed to use_table\n");
  80. pkg_free(col);
  81. return -1;
  82. }
  83. if (auth_dbf.query(auth_db_handle, keys, 0, vals, col, n, nc, 0, &res) < 0) {
  84. LM_ERR("failed to query database\n");
  85. pkg_free(col);
  86. if(res)
  87. auth_dbf.free_result(auth_db_handle, res);
  88. return -1;
  89. }
  90. pkg_free(col);
  91. if (RES_ROW_N(res) == 0) {
  92. if(res)
  93. auth_dbf.free_result(auth_db_handle, res);
  94. LM_DBG("no result for user \'%.*s%s%.*s\' in [%.*s]\n",
  95. user->len, user->s, (n==2)?"@":"",
  96. (n==2)?domain->len:0, (n==2)?domain->s:"",
  97. table->len, table->s);
  98. return -2;
  99. }
  100. for (cred=credentials, n=0; cred; cred=cred->next, n++) {
  101. if (db_val2pv_spec(msg, &RES_ROWS(res)[0].values[n], cred->spec) != 0) {
  102. if(res)
  103. auth_dbf.free_result(auth_db_handle, res);
  104. LM_ERR("Failed to convert value for column %.*s\n",
  105. RES_NAMES(res)[n]->len, RES_NAMES(res)[n]->s);
  106. return -3;
  107. }
  108. }
  109. if(res)
  110. auth_dbf.free_result(auth_db_handle, res);
  111. return 0;
  112. }
  113. static inline int get_ha1(struct username* _username, str* _domain,
  114. const str* _table, char* _ha1, db1_res_t** res)
  115. {
  116. pv_elem_t *cred;
  117. db_key_t keys[2];
  118. db_val_t vals[2];
  119. db_key_t *col;
  120. str result;
  121. int n, nc;
  122. col = pkg_malloc(sizeof(*col) * (credentials_n + 1));
  123. if (col == NULL) {
  124. LM_ERR("no more pkg memory\n");
  125. return -1;
  126. }
  127. keys[0] = &user_column;
  128. keys[1] = &domain_column;
  129. /* should we calculate the HA1, and is it calculated with domain? */
  130. col[0] = (_username->domain.len && !calc_ha1) ?
  131. (&pass_column_2) : (&pass_column);
  132. for (n = 0, cred=credentials; cred ; n++, cred=cred->next) {
  133. col[1 + n] = &cred->text;
  134. }
  135. VAL_TYPE(vals) = VAL_TYPE(vals + 1) = DB1_STR;
  136. VAL_NULL(vals) = VAL_NULL(vals + 1) = 0;
  137. VAL_STR(vals).s = _username->user.s;
  138. VAL_STR(vals).len = _username->user.len;
  139. if (_username->domain.len) {
  140. VAL_STR(vals + 1) = _username->domain;
  141. } else {
  142. VAL_STR(vals + 1) = *_domain;
  143. }
  144. n = (use_domain ? 2 : 1);
  145. nc = 1 + credentials_n;
  146. if (auth_dbf.use_table(auth_db_handle, _table) < 0) {
  147. LM_ERR("failed to use_table\n");
  148. pkg_free(col);
  149. return -1;
  150. }
  151. if (auth_dbf.query(auth_db_handle, keys, 0, vals, col, n, nc, 0, res) < 0) {
  152. LM_ERR("failed to query database\n");
  153. pkg_free(col);
  154. return -1;
  155. }
  156. pkg_free(col);
  157. if (RES_ROW_N(*res) == 0) {
  158. LM_DBG("no result for user \'%.*s@%.*s\'\n",
  159. _username->user.len, ZSW(_username->user.s),
  160. (use_domain ? (_domain->len) : 0), ZSW(_domain->s));
  161. return 1;
  162. }
  163. result.s = (char*)ROW_VALUES(RES_ROWS(*res))[0].val.string_val;
  164. result.len = strlen(result.s);
  165. if (calc_ha1) {
  166. /* Only plaintext passwords are stored in database,
  167. * we have to calculate HA1 */
  168. auth_api.calc_HA1(HA_MD5, &_username->whole, _domain, &result,
  169. 0, 0, _ha1);
  170. LM_DBG("HA1 string calculated: %s\n", _ha1);
  171. } else {
  172. memcpy(_ha1, result.s, result.len);
  173. _ha1[result.len] = '\0';
  174. }
  175. return 0;
  176. }
  177. /*
  178. * Generate AVPs from the database result
  179. */
  180. static int generate_avps(struct sip_msg* msg, db1_res_t* db_res)
  181. {
  182. pv_elem_t *cred;
  183. int i;
  184. for (cred=credentials, i=1; cred; cred=cred->next, i++) {
  185. if (db_val2pv_spec(msg, &RES_ROWS(db_res)[0].values[i], cred->spec) != 0) {
  186. LM_ERR("Failed to convert value for column %.*s\n",
  187. RES_NAMES(db_res)[i]->len, RES_NAMES(db_res)[i]->s);
  188. return -1;
  189. }
  190. }
  191. return 0;
  192. }
  193. /*
  194. * Authorize digest credentials and set the pointer to used hdr
  195. */
  196. static int digest_authenticate_hdr(sip_msg_t* msg, str *realm,
  197. str *table, hdr_types_t hftype, str *method, hdr_field_t **ahdr)
  198. {
  199. char ha1[256];
  200. int res;
  201. struct hdr_field* h;
  202. auth_body_t* cred;
  203. db1_res_t* result = NULL;
  204. int ret;
  205. cred = 0;
  206. ret = AUTH_ERROR;
  207. ret = auth_api.pre_auth(msg, realm, hftype, &h, NULL);
  208. switch(ret) {
  209. case NONCE_REUSED:
  210. LM_DBG("nonce reused");
  211. ret = AUTH_NONCE_REUSED;
  212. goto end;
  213. case STALE_NONCE:
  214. LM_DBG("stale nonce\n");
  215. ret = AUTH_STALE_NONCE;
  216. goto end;
  217. case NO_CREDENTIALS:
  218. LM_DBG("no credentials\n");
  219. ret = AUTH_NO_CREDENTIALS;
  220. goto end;
  221. case ERROR:
  222. case BAD_CREDENTIALS:
  223. LM_DBG("error or bad credentials\n");
  224. ret = AUTH_ERROR;
  225. goto end;
  226. case CREATE_CHALLENGE:
  227. LM_ERR("CREATE_CHALLENGE is not a valid state\n");
  228. ret = AUTH_ERROR;
  229. goto end;
  230. case DO_RESYNCHRONIZATION:
  231. LM_ERR("DO_RESYNCHRONIZATION is not a valid state\n");
  232. ret = AUTH_ERROR;
  233. goto end;
  234. case NOT_AUTHENTICATED:
  235. LM_DBG("not authenticated\n");
  236. ret = AUTH_ERROR;
  237. goto end;
  238. case DO_AUTHENTICATION:
  239. break;
  240. case AUTHENTICATED:
  241. ret = AUTH_OK;
  242. goto end;
  243. }
  244. cred = (auth_body_t*)h->parsed;
  245. if(ahdr!=NULL) *ahdr = h;
  246. res = get_ha1(&cred->digest.username, realm, table, ha1, &result);
  247. if (res < 0) {
  248. /* Error while accessing the database */
  249. ret = AUTH_ERROR;
  250. goto end;
  251. }
  252. if (res > 0) {
  253. /* Username not found in the database */
  254. ret = AUTH_USER_UNKNOWN;
  255. goto end;
  256. }
  257. /* Recalculate response, it must be same to authorize successfully */
  258. ret = auth_api.check_response(&(cred->digest), method, ha1);
  259. if(ret==AUTHENTICATED) {
  260. ret = AUTH_OK;
  261. switch(auth_api.post_auth(msg, h)) {
  262. case AUTHENTICATED:
  263. generate_avps(msg, result);
  264. break;
  265. default:
  266. ret = AUTH_ERROR;
  267. break;
  268. }
  269. } else {
  270. if(ret==NOT_AUTHENTICATED)
  271. ret = AUTH_INVALID_PASSWORD;
  272. else
  273. ret = AUTH_ERROR;
  274. }
  275. end:
  276. if(result)
  277. auth_dbf.free_result(auth_db_handle, result);
  278. return ret;
  279. }
  280. /*
  281. * Authorize digest credentials
  282. */
  283. static int digest_authenticate(sip_msg_t* msg, str *realm,
  284. str *table, hdr_types_t hftype, str *method)
  285. {
  286. return digest_authenticate_hdr(msg, realm, table, hftype, method, NULL);
  287. }
  288. /*
  289. * Authenticate using Proxy-Authorize header field
  290. */
  291. int proxy_authenticate(struct sip_msg* _m, char* _realm, char* _table)
  292. {
  293. str srealm;
  294. str stable;
  295. if(_table==NULL) {
  296. LM_ERR("invalid table parameter\n");
  297. return AUTH_ERROR;
  298. }
  299. stable.s = _table;
  300. stable.len = strlen(stable.s);
  301. if (get_str_fparam(&srealm, _m, (fparam_t*)_realm) < 0) {
  302. LM_ERR("failed to get realm value\n");
  303. return AUTH_ERROR;
  304. }
  305. if (srealm.len==0)
  306. {
  307. LM_ERR("invalid realm parameter - empty value\n");
  308. return AUTH_ERROR;
  309. }
  310. LM_DBG("realm value [%.*s]\n", srealm.len, srealm.s);
  311. return digest_authenticate(_m, &srealm, &stable, HDR_PROXYAUTH_T,
  312. &_m->first_line.u.request.method);
  313. }
  314. /*
  315. * Authenticate using WWW-Authorize header field
  316. */
  317. int www_authenticate(struct sip_msg* _m, char* _realm, char* _table)
  318. {
  319. str srealm;
  320. str stable;
  321. if(_table==NULL) {
  322. LM_ERR("invalid table parameter\n");
  323. return AUTH_ERROR;
  324. }
  325. stable.s = _table;
  326. stable.len = strlen(stable.s);
  327. if (get_str_fparam(&srealm, _m, (fparam_t*)_realm) < 0) {
  328. LM_ERR("failed to get realm value\n");
  329. return AUTH_ERROR;
  330. }
  331. if (srealm.len==0)
  332. {
  333. LM_ERR("invalid realm parameter - empty value\n");
  334. return AUTH_ERROR;
  335. }
  336. LM_DBG("realm value [%.*s]\n", srealm.len, srealm.s);
  337. return digest_authenticate(_m, &srealm, &stable, HDR_AUTHORIZATION_T,
  338. &_m->first_line.u.request.method);
  339. }
  340. int www_authenticate2(struct sip_msg* _m, char* _realm, char* _table, char *_method)
  341. {
  342. str srealm;
  343. str stable;
  344. str smethod;
  345. if(_table==NULL) {
  346. LM_ERR("invalid table parameter\n");
  347. return AUTH_ERROR;
  348. }
  349. stable.s = _table;
  350. stable.len = strlen(stable.s);
  351. if (get_str_fparam(&srealm, _m, (fparam_t*)_realm) < 0) {
  352. LM_ERR("failed to get realm value\n");
  353. return AUTH_ERROR;
  354. }
  355. if (srealm.len==0)
  356. {
  357. LM_ERR("invalid realm parameter - empty value\n");
  358. return AUTH_ERROR;
  359. }
  360. LM_DBG("realm value [%.*s]\n", srealm.len, srealm.s);
  361. if (get_str_fparam(&smethod, _m, (fparam_t*)_method) < 0) {
  362. LM_ERR("failed to get method value\n");
  363. return AUTH_ERROR;
  364. }
  365. if (smethod.len==0)
  366. {
  367. LM_ERR("invalid method parameter - empty value\n");
  368. return AUTH_ERROR;
  369. }
  370. LM_DBG("method value [%.*s]\n", smethod.len, smethod.s);
  371. return digest_authenticate(_m, &srealm, &stable, HDR_AUTHORIZATION_T,
  372. &smethod);
  373. }
  374. /*
  375. * Authenticate using WWW/Proxy-Authorize header field
  376. */
  377. int auth_check(struct sip_msg* _m, char* _realm, char* _table, char *_flags)
  378. {
  379. str srealm;
  380. str stable;
  381. int iflags;
  382. int ret;
  383. hdr_field_t *hdr;
  384. sip_uri_t *uri = NULL;
  385. sip_uri_t *turi = NULL;
  386. sip_uri_t *furi = NULL;
  387. if ((_m->REQ_METHOD == METHOD_ACK) || (_m->REQ_METHOD == METHOD_CANCEL)) {
  388. return AUTH_OK;
  389. }
  390. if(_m==NULL || _realm==NULL || _table==NULL || _flags==NULL) {
  391. LM_ERR("invalid parameters\n");
  392. return AUTH_ERROR;
  393. }
  394. if (get_str_fparam(&srealm, _m, (fparam_t*)_realm) < 0) {
  395. LM_ERR("failed to get realm value\n");
  396. return AUTH_ERROR;
  397. }
  398. if (srealm.len==0) {
  399. LM_ERR("invalid realm parameter - empty value\n");
  400. return AUTH_ERROR;
  401. }
  402. if (get_str_fparam(&stable, _m, (fparam_t*)_table) < 0) {
  403. LM_ERR("failed to get realm value\n");
  404. return AUTH_ERROR;
  405. }
  406. if (stable.len==0) {
  407. LM_ERR("invalid table parameter - empty value\n");
  408. return AUTH_ERROR;
  409. }
  410. if(fixup_get_ivalue(_m, (gparam_p)_flags, &iflags)!=0)
  411. {
  412. LM_ERR("invalid flags parameter\n");
  413. return -1;
  414. }
  415. LM_DBG("realm [%.*s] table [%.*s] flags [%d]\n", srealm.len, srealm.s,
  416. stable.len, stable.s, iflags);
  417. hdr = NULL;
  418. if(_m->REQ_METHOD==METHOD_REGISTER)
  419. ret = digest_authenticate_hdr(_m, &srealm, &stable, HDR_AUTHORIZATION_T,
  420. &_m->first_line.u.request.method, &hdr);
  421. else
  422. ret = digest_authenticate_hdr(_m, &srealm, &stable, HDR_PROXYAUTH_T,
  423. &_m->first_line.u.request.method, &hdr);
  424. if(ret==AUTH_OK && hdr!=NULL && (iflags&AUTH_CHECK_ID_F)) {
  425. srealm = ((auth_body_t*)(hdr->parsed))->digest.username.user;
  426. if((furi=parse_from_uri(_m))==NULL)
  427. return AUTH_ERROR;
  428. if(_m->REQ_METHOD==METHOD_REGISTER || _m->REQ_METHOD==METHOD_PUBLISH) {
  429. if((turi=parse_to_uri(_m))==NULL)
  430. return AUTH_ERROR;
  431. uri = turi;
  432. } else {
  433. uri = furi;
  434. }
  435. if(!((iflags&AUTH_CHECK_SKIPFWD_F)
  436. && (_m->REQ_METHOD==METHOD_INVITE || _m->REQ_METHOD==METHOD_BYE
  437. || _m->REQ_METHOD==METHOD_PRACK || _m->REQ_METHOD==METHOD_UPDATE
  438. || _m->REQ_METHOD==METHOD_MESSAGE))) {
  439. if(srealm.len!=uri->user.len
  440. || strncmp(srealm.s, uri->user.s, srealm.len)!=0)
  441. return AUTH_USER_MISMATCH;
  442. }
  443. if(_m->REQ_METHOD==METHOD_REGISTER || _m->REQ_METHOD==METHOD_PUBLISH) {
  444. /* check from==to */
  445. if(furi->user.len!=turi->user.len
  446. || strncmp(furi->user.s, turi->user.s, furi->user.len)!=0)
  447. return AUTH_USER_MISMATCH;
  448. if(use_domain!=0 && (furi->host.len!=turi->host.len
  449. || strncmp(furi->host.s, turi->host.s, furi->host.len)!=0))
  450. return AUTH_USER_MISMATCH;
  451. /* check r-uri==from for publish */
  452. if(_m->REQ_METHOD==METHOD_PUBLISH) {
  453. if(parse_sip_msg_uri(_m)<0)
  454. return AUTH_ERROR;
  455. uri = &_m->parsed_uri;
  456. if(furi->user.len!=uri->user.len
  457. || strncmp(furi->user.s, uri->user.s, furi->user.len)!=0)
  458. return AUTH_USER_MISMATCH;
  459. if(use_domain!=0 && (furi->host.len!=uri->host.len
  460. || strncmp(furi->host.s, uri->host.s, furi->host.len)!=0))
  461. return AUTH_USER_MISMATCH;
  462. }
  463. }
  464. return AUTH_OK;
  465. }
  466. return ret;
  467. }
  468. /**
  469. * @brief bind functions to AUTH_DB API structure
  470. */
  471. int bind_auth_db(auth_db_api_t *api)
  472. {
  473. if (!api) {
  474. ERR("Invalid parameter value\n");
  475. return -1;
  476. }
  477. api->digest_authenticate = digest_authenticate;
  478. return 0;
  479. }