Browse code

auth: new function pv_auth_check(...)

- equivalent of auth_check(...) from auth_db, but taking the password
from a PV -- combines pv_proxy_authenticate() and
pv_www_authenticate()
- new module parameter use_domain that controls whether the domain part
of URIs should be used or not to make the identity checks upon
authentication with pv_auth_check(...)

Daniel-Constantin Mierla authored on 03/10/2012 18:25:52
Showing 5 changed files
... ...
@@ -38,6 +38,7 @@ Daniel-Constantin Mierla
38 38
         1.3.12. nonce_auth_max_drift (integer)
39 39
         1.3.13. force_stateless_reply (boolean)
40 40
         1.3.14. realm_prefix (string)
41
+        1.3.15. use_domain (boolean)
41 42
 
42 43
    1.4. Functions
43 44
 
... ...
@@ -48,7 +49,8 @@ Daniel-Constantin Mierla
48 49
         1.4.5. auth_challenge(realm, flags)
49 50
         1.4.6. pv_www_authenticate(realm, passwd, flags)
50 51
         1.4.7. pv_proxy_authenticate(realm, passwd, flags)
51
-        1.4.8. auth_get_www_authenticate(realm, flags, pvdst)
52
+        1.4.8. pv_auth_check(realm, passwd, flags, checks)
53
+        1.4.9. auth_get_www_authenticate(realm, flags, pvdst)
52 54
 
53 55
 1.1. Overview
54 56
 
... ...
@@ -513,6 +515,16 @@ modparam("auth", "force_stateless_reply", 1)
513 515
    Example 14. realm_prefix parameter example
514 516
 modparam("auth", "realm_prefix", "sip.")
515 517
 
518
+1.3.15. use_domain (boolean)
519
+
520
+   If set to 1, pv_auth_check() uses domain parts of the URIs to check
521
+   user identity.
522
+
523
+   Example 15. force_stateless_reply example
524
+...
525
+modparam("auth", "use_domain", 1)
526
+...
527
+
516 528
 1.4. Functions
517 529
 
518 530
 1.4.1. consume_credentials()
... ...
@@ -525,7 +537,7 @@ modparam("auth", "realm_prefix", "sip.")
525 537
    little bit shorter. The function must be called after www_authorize,
526 538
    proxy_authorize, www_authenticate or proxy_authenticate.
527 539
 
528
-   Example 15. consume_credentials example
540
+   Example 16. consume_credentials example
529 541
 ...
530 542
 if (www_authenticate("realm", "subscriber")) {
531 543
     consume_credentials();
... ...
@@ -538,7 +550,7 @@ if (www_authenticate("realm", "subscriber")) {
538 550
    Proxy-Authorization header with provided realm. The parameter can be
539 551
    string with pseudo-variables.
540 552
 
541
-   Example 16. consume_credentials example
553
+   Example 17. consume_credentials example
542 554
 ...
543 555
 if (has_credentials("myrealm")) {
544 556
     ...
... ...
@@ -574,7 +586,7 @@ if (has_credentials("myrealm")) {
574 586
 
575 587
    This function can be used from REQUEST_ROUTE.
576 588
 
577
-   Example 17. www_challenge usage
589
+   Example 18. www_challenge usage
578 590
 ...
579 591
 if (!www_authenticate("$td", "subscriber")) {
580 592
         www_challenge("$td", "1");
... ...
@@ -596,7 +608,7 @@ if (!www_authenticate("$td", "subscriber")) {
596 608
 
597 609
    This function can be used from REQUEST_ROUTE.
598 610
 
599
-   Example 18. proxy_challenge usage
611
+   Example 19. proxy_challenge usage
600 612
 ...
601 613
 if (!proxy_authenticate("$fd", "subscriber")) {
602 614
         proxy_challenge("$fd", "1");
... ...
@@ -615,7 +627,7 @@ if (!proxy_authenticate("$fd", "subscriber")) {
615 627
 
616 628
    This function can be used from REQUEST_ROUTE.
617 629
 
618
-   Example 19. proxy_challenge usage
630
+   Example 20. proxy_challenge usage
619 631
 ...
620 632
 if (!auth_check("$fd", "subscriber", "1")) {
621 633
         auth_challenge("$fd", "1");
... ...
@@ -666,7 +678,7 @@ if (!auth_check("$fd", "subscriber", "1")) {
666 678
 
667 679
    This function can be used from REQUEST_ROUTE.
668 680
 
669
-   Example 20. pv_www_authenticate usage
681
+   Example 21. pv_www_authenticate usage
670 682
 ...
671 683
 if (!pv_www_authenticate("$td", "123abc", "0")) {
672 684
         www_challenge("$td", "1");
... ...
@@ -688,7 +700,7 @@ if (!pv_www_authenticate("$td", "123abc", "0")) {
688 700
 
689 701
    This function can be used from REQUEST_ROUTE.
690 702
 
691
-   Example 21. pv_proxy_authenticate usage
703
+   Example 22. pv_proxy_authenticate usage
692 704
 ...
693 705
 $avp(password)="xyz";
694 706
 if (!pv_proxy_authenticate("$fd", "$avp(password)", "0")) {
... ...
@@ -696,7 +708,32 @@ if (!pv_proxy_authenticate("$fd", "$avp(password)", "0")) {
696 708
 };
697 709
 ...
698 710
 
699
-1.4.8. auth_get_www_authenticate(realm, flags, pvdst)
711
+1.4.8. pv_auth_check(realm, passwd, flags, checks)
712
+
713
+   The function combines the functionalities of pv_www_authenticate and
714
+   pv_proxy_authenticate, first being exectuted if the SIP request is a
715
+   REGISTER, the second for the rest.
716
+
717
+   Meaning of the first three parameters is the same as for
718
+   pv_www_authenticate(realm, passwd, flags).
719
+
720
+   Parameter checks can be used to control the behaviour of the function.
721
+   If it is 1, then the function will check to see if the authentication
722
+   username matches either To or From header username, a matter of whether
723
+   it is for a REGISTER request or not. The parameter may be a pseudo
724
+   variable.
725
+
726
+   This function can be used from REQUEST_ROUTE.
727
+
728
+   Example 23. pv_proxy_authenticate usage
729
+...
730
+$avp(password)="xyz";
731
+if (!pv_auth_check("$fd", "$avp(password)", "0", "1")) {
732
+        proxy_challenge("$fd", "1");
733
+};
734
+...
735
+
736
+1.4.9. auth_get_www_authenticate(realm, flags, pvdst)
700 737
 
701 738
    Build WWW-Authentication header and set the resulting value in 'pvdest'
702 739
    parameter.
... ...
@@ -706,7 +743,7 @@ if (!pv_proxy_authenticate("$fd", "$avp(password)", "0")) {
706 743
 
707 744
    This function can be used from ANY_ROUTE.
708 745
 
709
-   Example 22. auth_get_www_authenticate
746
+   Example 24. auth_get_www_authenticate
710 747
 ...
711 748
 if (auth_get_www_authenticate("$fd", "0", "$var(wauth)")) {
712 749
         xlog("www authenticate header is [$var(wauth)]\n");
... ...
@@ -56,6 +56,11 @@ typedef enum auth_cfg_result {
56 56
 } auth_cfg_result_t;
57 57
 
58 58
 
59
+/**
60
+ * flags for checks in auth functions
61
+ */
62
+#define AUTH_CHECK_ID_F 1<<0
63
+
59 64
 /**
60 65
  * return codes to auth API functions
61 66
  */
... ...
@@ -46,6 +46,9 @@
46 46
 #include "../../dprint.h"
47 47
 #include "../../mem/mem.h"
48 48
 #include "../../parser/digest/digest.h"
49
+#include "../../parser/parse_from.h"
50
+#include "../../parser/parse_to.h"
51
+#include "../../parser/parse_uri.h"
49 52
 #include "../../data_lump.h"
50 53
 #include "../../data_lump_rpl.h"
51 54
 #include "../../error.h"
... ...
@@ -91,6 +94,9 @@ static int pv_proxy_authenticate(struct sip_msg* msg, char* realm,
91 94
 static int pv_www_authenticate(struct sip_msg* msg, char* realm,
92 95
 		char *passwd, char *flags);
93 96
 static int fixup_pv_auth(void **param, int param_no);
97
+static int pv_auth_check(sip_msg_t *msg, char *realm,
98
+		char *passwd, char *flags, char *checks);
99
+static int fixup_pv_auth_check(void **param, int param_no);
94 100
 
95 101
 static int proxy_challenge(struct sip_msg *msg, char* realm, char *flags);
96 102
 static int www_challenge(struct sip_msg *msg, char* realm, char *flags);
... ...
@@ -113,6 +119,8 @@ int force_stateless_reply = 0; /* Always send reply statelessly */
113 119
 /*! Prefix to strip from realm */
114 120
 str auth_realm_prefix = {"", 0};
115 121
 
122
+static int auth_use_domain = 0;
123
+
116 124
 str secret1;
117 125
 str secret2;
118 126
 char* sec_rand1 = 0;
... ...
@@ -166,6 +174,8 @@ static cmd_export_t cmds[] = {
166 174
 			fixup_auth_get_www_authenticate, REQUEST_ROUTE},
167 175
     {"has_credentials",        w_has_credentials,                    1,
168 176
 			fixup_spve_null, REQUEST_ROUTE},
177
+    {"pv_auth_check",         (cmd_function)pv_auth_check,           4,
178
+			fixup_pv_auth_check, REQUEST_ROUTE},
169 179
     {"bind_auth_s",           (cmd_function)bind_auth_s, 0, 0, 0        },
170 180
     {0, 0, 0, 0, 0}
171 181
 };
... ...
@@ -192,9 +202,10 @@ static param_export_t params[] = {
192 202
 	{"one_time_nonce"  ,       PARAM_INT,    &otn_enabled           },
193 203
 	{"otn_in_flight_no",       PARAM_INT,    &otn_in_flight_no      },
194 204
 	{"otn_in_flight_order",    PARAM_INT,    &otn_in_flight_k       },
195
-	{"nid_pool_no",            PARAM_INT,    &nid_pool_no            },
205
+	{"nid_pool_no",            PARAM_INT,    &nid_pool_no           },
196 206
     {"force_stateless_reply",  PARAM_INT,    &force_stateless_reply },
197 207
 	{"realm_prefix",           PARAM_STRING, &auth_realm_prefix.s   },
208
+    {"use_domain",             PARAM_INT,    &auth_use_domain       },
198 209
     {0, 0, 0}
199 210
 };
200 211
 
... ...
@@ -637,6 +648,118 @@ error:
637 648
 	return AUTH_ERROR;
638 649
 }
639 650
 
651
+/**
652
+ *
653
+ */
654
+static int pv_auth_check(sip_msg_t *msg, char *realm,
655
+		char *passwd, char *flags, char *checks)
656
+{
657
+    int vflags = 0;
658
+    int vchecks = 0;
659
+    str srealm  = {0, 0};
660
+    str spasswd = {0, 0};
661
+	int ret;
662
+	hdr_field_t *hdr;
663
+	sip_uri_t *uri = NULL;
664
+	sip_uri_t *turi = NULL;
665
+	sip_uri_t *furi = NULL;
666
+
667
+	if(msg==NULL) {
668
+		LM_ERR("invalid msg parameter\n");
669
+		return AUTH_ERROR;
670
+	}
671
+
672
+	if ((msg->REQ_METHOD == METHOD_ACK) || (msg->REQ_METHOD == METHOD_CANCEL)) {
673
+		return AUTH_OK;
674
+	}
675
+
676
+	if(realm==NULL || passwd==NULL || flags==NULL || checks==NULL) {
677
+		LM_ERR("invalid parameters\n");
678
+		return AUTH_ERROR;
679
+	}
680
+
681
+	if (get_str_fparam(&srealm, msg, (fparam_t*)realm) < 0) {
682
+		LM_ERR("failed to get realm value\n");
683
+		return AUTH_ERROR;
684
+	}
685
+
686
+	if(srealm.len==0) {
687
+		LM_ERR("invalid realm value - empty content\n");
688
+		return AUTH_ERROR;
689
+	}
690
+
691
+	if (get_str_fparam(&spasswd, msg, (fparam_t*)passwd) < 0) {
692
+		LM_ERR("failed to get passwd value\n");
693
+		return AUTH_ERROR;
694
+	}
695
+
696
+	if(spasswd.len==0) {
697
+		LM_ERR("invalid password value - empty content\n");
698
+		return AUTH_ERROR;
699
+	}
700
+
701
+	if (get_int_fparam(&vflags, msg, (fparam_t*)flags) < 0) {
702
+		LM_ERR("invalid flags value\n");
703
+		return AUTH_ERROR;
704
+	}
705
+
706
+	if (get_int_fparam(&vchecks, msg, (fparam_t*)checks) < 0) {
707
+		LM_ERR("invalid checks value\n");
708
+		return AUTH_ERROR;
709
+	}
710
+	LM_DBG("realm [%.*s] flags [%d] checks [%d]\n", srealm.len, srealm.s,
711
+			vflags, vchecks);
712
+
713
+	if(msg->REQ_METHOD==METHOD_REGISTER)
714
+		ret = pv_authenticate(msg, &srealm, &spasswd, vflags, HDR_AUTHORIZATION_T);
715
+	else
716
+		ret = pv_authenticate(msg, &srealm, &spasswd, vflags, HDR_PROXYAUTH_T);
717
+
718
+	if(ret==AUTH_OK && (vflags&AUTH_CHECK_ID_F)) {
719
+		hdr = (msg->proxy_auth==0)?msg->authorization:msg->proxy_auth;
720
+		srealm = ((auth_body_t*)(hdr->parsed))->digest.username.user;
721
+
722
+		if((furi=parse_from_uri(msg))==NULL)
723
+			return AUTH_ERROR;
724
+
725
+		if(msg->REQ_METHOD==METHOD_REGISTER || msg->REQ_METHOD==METHOD_PUBLISH) {
726
+			if((turi=parse_to_uri(msg))==NULL)
727
+				return AUTH_ERROR;
728
+			uri = turi;
729
+		} else {
730
+			uri = furi;
731
+		}
732
+		if(srealm.len!=uri->user.len
733
+					|| strncmp(srealm.s, uri->user.s, srealm.len)!=0)
734
+			return AUTH_USER_MISMATCH;
735
+
736
+		if(msg->REQ_METHOD==METHOD_REGISTER || msg->REQ_METHOD==METHOD_PUBLISH) {
737
+			/* check from==to */
738
+			if(furi->user.len!=turi->user.len
739
+					|| strncmp(furi->user.s, turi->user.s, furi->user.len)!=0)
740
+				return AUTH_USER_MISMATCH;
741
+			if(auth_use_domain!=0 && (furi->host.len!=turi->host.len
742
+					|| strncmp(furi->host.s, turi->host.s, furi->host.len)!=0))
743
+				return AUTH_USER_MISMATCH;
744
+			/* check r-uri==from for publish */
745
+			if(msg->REQ_METHOD==METHOD_PUBLISH) {
746
+				if(parse_sip_msg_uri(msg)<0)
747
+					return AUTH_ERROR;
748
+				uri = &msg->parsed_uri;
749
+				if(furi->user.len!=uri->user.len
750
+						|| strncmp(furi->user.s, uri->user.s, furi->user.len)!=0)
751
+					return AUTH_USER_MISMATCH;
752
+				if(auth_use_domain!=0 && (furi->host.len!=uri->host.len
753
+						|| strncmp(furi->host.s, uri->host.s, furi->host.len)!=0))
754
+					return AUTH_USER_MISMATCH;
755
+				}
756
+		}
757
+		return AUTH_OK;
758
+	}
759
+
760
+	return ret;
761
+}
762
+
640 763
 /**
641 764
  * @brief fixup function for pv_{www,proxy}_authenticate
642 765
  */
... ...
@@ -657,6 +780,28 @@ static int fixup_pv_auth(void **param, int param_no)
657 780
 	return 0;
658 781
 }
659 782
 
783
+/**
784
+ * @brief fixup function for pv_{www,proxy}_authenticate
785
+ */
786
+static int fixup_pv_auth_check(void **param, int param_no)
787
+{
788
+	if(strlen((char*)*param)<=0) {
789
+		LM_ERR("empty parameter %d not allowed\n", param_no);
790
+		return -1;
791
+	}
792
+
793
+	switch(param_no) {
794
+		case 1:
795
+		case 2:
796
+			return fixup_var_pve_str_12(param, 1);
797
+		case 3:
798
+		case 4:
799
+			return fixup_var_int_12(param, 1);
800
+	}
801
+	return 0;
802
+}
803
+
804
+
660 805
 
661 806
 /**
662 807
  *
... ...
@@ -326,6 +326,43 @@ if (!pv_proxy_authenticate("$fd", "$avp(password)", "0")) {
326 326
 		</example>
327 327
 	</section>
328 328
 
329
+	<section id="pv_auth_check">
330
+		<title>
331
+			<function moreinfo="none">pv_auth_check(realm, passwd, flags, checks)</function>
332
+		</title>
333
+		<para>
334
+		The function combines the functionalities of
335
+		<function moreinfo="none">pv_www_authenticate</function> and
336
+		<function moreinfo="none">pv_proxy_authenticate</function>, first being
337
+		exectuted if the SIP request is a REGISTER, the second for the rest.
338
+		</para>
339
+		<para>
340
+		Meaning of the first three parameters is the same as for
341
+		pv_www_authenticate(realm, passwd, flags).
342
+		</para>
343
+		<para>
344
+		Parameter <emphasis>checks</emphasis> can be used to control the
345
+		behaviour of the function. If it is 1, then the function will
346
+		check to see if the authentication username matches either To or
347
+		From header username, a matter of whether it is for a REGISTER
348
+		request or not.	The parameter may be a pseudo variable.
349
+		</para>
350
+		<para>
351
+		This function can be used from REQUEST_ROUTE.
352
+		</para>
353
+		<example>
354
+		<title>pv_proxy_authenticate usage</title>
355
+		<programlisting format="linespecific">
356
+...
357
+$avp(password)="xyz";
358
+if (!pv_auth_check("$fd", "$avp(password)", "0", "1")) {
359
+	proxy_challenge("$fd", "1");
360
+};
361
+...
362
+</programlisting>
363
+		</example>
364
+	</section>
365
+
329 366
 	<section id="auth_get_www_authenticate">
330 367
 		<title>
331 368
 			<function moreinfo="none">auth_get_www_authenticate(realm, flags, pvdst)</function>
... ...
@@ -636,6 +636,7 @@ modparam("auth", "force_stateless_reply", 1)
636 636
 	    </programlisting>
637 637
 	</example>
638 638
 	</section>
639
+
639 640
 	<section id="realm_prefix">
640 641
 		<title><varname>realm_prefix</varname> (string)</title>
641 642
 		<para>
... ...
@@ -657,4 +658,21 @@ modparam("auth", "realm_prefix", "sip.")
657 658
 </programlisting>
658 659
 		</example>
659 660
 	</section>
661
+
662
+	<section id="auth.use_domain">
663
+	<title><varname>use_domain</varname> (boolean)</title>
664
+	<para>
665
+		If set to 1, <function>pv_auth_check()</function> uses
666
+		domain parts of the URIs to check user identity.
667
+	</para>
668
+	<example>
669
+	    <title>force_stateless_reply example</title>
670
+	    <programlisting>
671
+...
672
+modparam("auth", "use_domain", 1)
673
+...
674
+	    </programlisting>
675
+	</example>
676
+	</section>
677
+
660 678
 </section>