Lines 748-753
Link Here
|
748 |
the_compare_node.attrib = (char *)attrib; |
748 |
the_compare_node.attrib = (char *)attrib; |
749 |
the_compare_node.value = (char *)value; |
749 |
the_compare_node.value = (char *)value; |
750 |
the_compare_node.result = 0; |
750 |
the_compare_node.result = 0; |
|
|
751 |
the_compare_node.sgl_processed = 0; |
752 |
the_compare_node.subgroupList = NULL; |
751 |
|
753 |
|
752 |
compare_nodep = util_ald_cache_fetch(curl->compare_cache, |
754 |
compare_nodep = util_ald_cache_fetch(curl->compare_cache, |
753 |
&the_compare_node); |
755 |
&the_compare_node); |
Lines 760-783
Link Here
|
760 |
} |
762 |
} |
761 |
else { |
763 |
else { |
762 |
/* ...and it is good */ |
764 |
/* ...and it is good */ |
763 |
/* unlock this read lock */ |
|
|
764 |
LDAP_CACHE_UNLOCK(); |
765 |
if (LDAP_COMPARE_TRUE == compare_nodep->result) { |
765 |
if (LDAP_COMPARE_TRUE == compare_nodep->result) { |
766 |
ldc->reason = "Comparison true (cached)"; |
766 |
ldc->reason = "Comparison true (cached)"; |
767 |
return compare_nodep->result; |
|
|
768 |
} |
767 |
} |
769 |
else if (LDAP_COMPARE_FALSE == compare_nodep->result) { |
768 |
else if (LDAP_COMPARE_FALSE == compare_nodep->result) { |
770 |
ldc->reason = "Comparison false (cached)"; |
769 |
ldc->reason = "Comparison false (cached)"; |
771 |
return compare_nodep->result; |
|
|
772 |
} |
770 |
} |
773 |
else if (LDAP_NO_SUCH_ATTRIBUTE == compare_nodep->result) { |
771 |
else if (LDAP_NO_SUCH_ATTRIBUTE == compare_nodep->result) { |
774 |
ldc->reason = "Comparison no such attribute (cached)"; |
772 |
ldc->reason = "Comparison no such attribute (cached)"; |
775 |
return compare_nodep->result; |
|
|
776 |
} |
773 |
} |
777 |
else { |
774 |
else { |
778 |
ldc->reason = "Comparison undefined (cached)"; |
775 |
ldc->reason = "Comparison undefined (cached)"; |
779 |
return compare_nodep->result; |
|
|
780 |
} |
776 |
} |
|
|
777 |
|
778 |
/* record the result code to return with the reason... */ |
779 |
result = compare_nodep->result; |
780 |
/* and unlock this read lock */ |
781 |
LDAP_CACHE_UNLOCK(); |
782 |
return result; |
781 |
} |
783 |
} |
782 |
} |
784 |
} |
783 |
/* unlock this read lock */ |
785 |
/* unlock this read lock */ |
Lines 789-794
Link Here
|
789 |
/* too many failures */ |
791 |
/* too many failures */ |
790 |
return result; |
792 |
return result; |
791 |
} |
793 |
} |
|
|
794 |
|
792 |
if (LDAP_SUCCESS != (result = uldap_connection_open(r, ldc))) { |
795 |
if (LDAP_SUCCESS != (result = uldap_connection_open(r, ldc))) { |
793 |
/* connect failed */ |
796 |
/* connect failed */ |
794 |
return result; |
797 |
return result; |
Lines 814-819
Link Here
|
814 |
LDAP_CACHE_LOCK(); |
817 |
LDAP_CACHE_LOCK(); |
815 |
the_compare_node.lastcompare = curtime; |
818 |
the_compare_node.lastcompare = curtime; |
816 |
the_compare_node.result = result; |
819 |
the_compare_node.result = result; |
|
|
820 |
the_compare_node.sgl_processed = 0; |
821 |
the_compare_node.subgroupList = NULL; |
817 |
|
822 |
|
818 |
/* If the node doesn't exist then insert it, otherwise just update |
823 |
/* If the node doesn't exist then insert it, otherwise just update |
819 |
* it with the last results |
824 |
* it with the last results |
Lines 825-831
Link Here
|
825 |
|| (strcmp(the_compare_node.attrib,compare_nodep->attrib) != 0) |
830 |
|| (strcmp(the_compare_node.attrib,compare_nodep->attrib) != 0) |
826 |
|| (strcmp(the_compare_node.value, compare_nodep->value) != 0)) |
831 |
|| (strcmp(the_compare_node.value, compare_nodep->value) != 0)) |
827 |
{ |
832 |
{ |
828 |
util_ald_cache_insert(curl->compare_cache, &the_compare_node); |
833 |
void *junk; |
|
|
834 |
|
835 |
junk = util_ald_cache_insert(curl->compare_cache, &the_compare_node); |
836 |
if(junk == NULL) { |
837 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "[%" APR_PID_T_FMT "] cache_compare: Cache insertion failure.", getpid()); |
838 |
} |
829 |
} |
839 |
} |
830 |
else { |
840 |
else { |
831 |
compare_nodep->lastcompare = curtime; |
841 |
compare_nodep->lastcompare = curtime; |
Lines 849-854
Link Here
|
849 |
return result; |
859 |
return result; |
850 |
} |
860 |
} |
851 |
|
861 |
|
|
|
862 |
/* |
863 |
* Does a recursive lookup operation to try to find a user within (cached) nested |
864 |
* groups. It accepts a cache that it will use to lookup previous compare attempts. |
865 |
* We cache two kinds of compares (require group compares) and (require user |
866 |
* compares). Each compare has a different cache node: require group includes the DN; |
867 |
* require user does not because the require user cache is owned by the |
868 |
* |
869 |
* DON'T CALL THIS UNLESS YOU CALLED uldap_cache_compare FIRST!!!!! |
870 |
*/ |
871 |
static int uldap_cache_check_subgroups(request_rec *r, util_ldap_connection_t *ldc, |
872 |
const char *url, const char *dn, |
873 |
const char *attrib, const char *value, |
874 |
char **subgroupAttrs, apr_array_header_t *subgroupclasses, |
875 |
int cur_subgroup_depth, int max_subgroup_depth) |
876 |
{ |
877 |
int result = LDAP_COMPARE_FALSE; |
878 |
util_url_node_t *curl; |
879 |
util_url_node_t curnode; |
880 |
util_compare_node_t *compare_nodep; |
881 |
util_compare_node_t the_compare_node; |
882 |
util_compare_subgroup_t *tmp_local_sgl = NULL; |
883 |
int failures = 0; |
884 |
LDAPMessage *sga_res, *entry; |
885 |
apr_array_header_t *subgroups = apr_array_make(r->pool, 20, sizeof(char *)); |
886 |
|
887 |
util_ldap_state_t *st = (util_ldap_state_t *) |
888 |
ap_get_module_config(r->server->module_config, |
889 |
&ldap_module); |
890 |
|
891 |
/* |
892 |
* 1. Call uldap_cache_compare for each subgroupclass value to check the generic, |
893 |
* user-agnostic, cached group entry. This will create a new generic cache entry if there |
894 |
* wasn't one. If nothing returns LDAP_COMPARE_TRUE skip to step 5 since we have no groups. |
895 |
* 2. Lock The cache and get the generic cache entry. |
896 |
* 3. Check if there is already a subgrouplist in this generic group's cache entry. |
897 |
* A. If there is, go to step 4. |
898 |
* B. If there isn't: |
899 |
* i) Use ldap_search to get the full list |
900 |
* of subgroup "members" (which may include non-group "members"). |
901 |
* ii) Use uldap_cache_compare to strip the list down to just groups. |
902 |
* iii) Lock and add this stripped down list to the cache of the generic group. |
903 |
* 4. Loop through the sgl and call uldap_cache_compare (using the user info) for each |
904 |
* subgroup to see if the subgroup contains the user and to get the subgroups added to the |
905 |
* cache (with user-afinity, if they aren't already there). |
906 |
* A. If the user is in the subgroup, then we'll be returning LDAP_COMPARE_TRUE. |
907 |
* B. if the user isn't in the subgroup (LDAP_COMPARE_FALSE via uldap_cache_compare) then |
908 |
* recursively call this function to get the sub-subgroups added... |
909 |
* 5. Cleanup local allocations. |
910 |
* 6. Return the final result. |
911 |
*/ |
912 |
|
913 |
/* Stop looking at deeper levels of nested groups if we have reached the max. |
914 |
* Since we already checked the top-level group in uldap_cache_compare, we don't |
915 |
* need to check it again here - so if max_subgroup_depth is set to 0, we won't |
916 |
* check it (i.e. that is why we check < rather than <=). |
917 |
* We'll be calling uldap_cache_compare from here to check if the user is in the |
918 |
* next level before we recurse into that next level looking for more subgroups. |
919 |
*/ |
920 |
if (cur_subgroup_depth < max_subgroup_depth) { |
921 |
int base_sgcIndex = 0; |
922 |
int lcl_sgl_processedFlag = 0; |
923 |
struct mod_auth_ldap_groupattr_entry_t *sgc_ents = (struct mod_auth_ldap_groupattr_entry_t *) subgroupclasses->elts; |
924 |
|
925 |
/* 1. Check the "groupiness" of the specified basedn. Stopping at the first TRUE return. */ |
926 |
while ((base_sgcIndex < subgroupclasses->nelts) && (result != LDAP_COMPARE_TRUE)) { |
927 |
result = uldap_cache_compare(r, ldc, url, dn, "objectClass", sgc_ents[base_sgcIndex].name); |
928 |
if (result != LDAP_COMPARE_TRUE) { |
929 |
base_sgcIndex++; |
930 |
} |
931 |
} |
932 |
|
933 |
if (result != LDAP_COMPARE_TRUE) { |
934 |
/* The dn we were handed doesn't seem to be a group, how can we check for SUB-groups if this |
935 |
* isn't a group?!?!?! |
936 |
*/ |
937 |
ldc->reason = "DN failed group verification."; |
938 |
return result; |
939 |
} |
940 |
|
941 |
/* 2. Find previously created cache entry and check if there is already a subgrouplist. */ |
942 |
LDAP_CACHE_LOCK(); |
943 |
curnode.url = url; |
944 |
curl = util_ald_cache_fetch(st->util_ldap_cache, &curnode); |
945 |
LDAP_CACHE_UNLOCK(); |
946 |
|
947 |
if (curl && curl->compare_cache) { |
948 |
/* make a comparison to the cache */ |
949 |
LDAP_CACHE_LOCK(); |
950 |
|
951 |
the_compare_node.dn = (char *)dn; |
952 |
the_compare_node.attrib = (char *)"objectClass"; |
953 |
the_compare_node.value = (char *)sgc_ents[base_sgcIndex].name; |
954 |
the_compare_node.result = 0; |
955 |
the_compare_node.sgl_processed = 0; |
956 |
the_compare_node.subgroupList = NULL; |
957 |
|
958 |
compare_nodep = util_ald_cache_fetch(curl->compare_cache, &the_compare_node); |
959 |
|
960 |
if (compare_nodep == NULL) { |
961 |
/* Didn't find it. This shouldn't happen since we just called uldap_cache_compare. */ |
962 |
LDAP_CACHE_UNLOCK(); |
963 |
ldc->reason = "check_subgroups failed to find cached element."; |
964 |
return LDAP_COMPARE_FALSE; |
965 |
} |
966 |
else { |
967 |
/* Found the generic group entry... but the user isn't in this group or we wouldn't be here. */ |
968 |
lcl_sgl_processedFlag = compare_nodep->sgl_processed; |
969 |
if(compare_nodep->sgl_processed && compare_nodep->subgroupList) { |
970 |
/* Make a local copy of the subgroup list */ |
971 |
int i; |
972 |
tmp_local_sgl = apr_pcalloc(r->pool, sizeof(util_compare_subgroup_t)); |
973 |
tmp_local_sgl->len = compare_nodep->subgroupList->len; |
974 |
tmp_local_sgl->subgroupDNs = apr_pcalloc(r->pool, sizeof(char *) * compare_nodep->subgroupList->len); |
975 |
for (i = 0; i < compare_nodep->subgroupList->len; i++) { |
976 |
tmp_local_sgl->subgroupDNs[i] = apr_pstrdup(r->pool, compare_nodep->subgroupList->subgroupDNs[i]); |
977 |
} |
978 |
} |
979 |
} |
980 |
/* unlock this read lock */ |
981 |
LDAP_CACHE_UNLOCK(); |
982 |
} |
983 |
else { |
984 |
/* If we get here, something is wrong. Caches should have been created and |
985 |
this group entry should be found in the cache. */ |
986 |
ldc->reason = "check_subgroups failed to find any caches."; |
987 |
return LDAP_COMPARE_FALSE; |
988 |
} |
989 |
|
990 |
result = LDAP_COMPARE_FALSE; |
991 |
|
992 |
/* No cache entry had a processed SGL. Retrieve from LDAP server */ |
993 |
if ((lcl_sgl_processedFlag == 0) && (!tmp_local_sgl)) { |
994 |
start_over: |
995 |
/* 3.B. The cache didn't have any subgrouplist yet. Go check for subgroups. */ |
996 |
if (failures++ > 10) { |
997 |
/* too many failures */ |
998 |
return result; |
999 |
} |
1000 |
|
1001 |
if (LDAP_SUCCESS != (result = uldap_connection_open(r, ldc))) { |
1002 |
/* connect failed */ |
1003 |
return result; |
1004 |
} |
1005 |
|
1006 |
/* try to do the search */ |
1007 |
result = ldap_search_ext_s(ldc->ldap, (char *)dn, LDAP_SCOPE_BASE, |
1008 |
(char *)"cn=*", subgroupAttrs, 0, |
1009 |
NULL, NULL, NULL, APR_LDAP_SIZELIMIT, &sga_res); |
1010 |
if (result == LDAP_SERVER_DOWN) { |
1011 |
ldc->reason = "ldap_search_ext_s() for subgroups failed with server down"; |
1012 |
uldap_connection_unbind(ldc); |
1013 |
goto start_over; |
1014 |
} |
1015 |
|
1016 |
/* if there is an error (including LDAP_NO_SUCH_OBJECT) return now */ |
1017 |
if (result != LDAP_SUCCESS) { |
1018 |
ldc->reason = "ldap_search_ext_s() for subgroups failed"; |
1019 |
return result; |
1020 |
} |
1021 |
|
1022 |
entry = ldap_first_entry(ldc->ldap, sga_res); |
1023 |
|
1024 |
/* |
1025 |
* Get values for the provided sub-group attributes. |
1026 |
*/ |
1027 |
if (subgroupAttrs) { |
1028 |
int indx = 0, tmp_sgcIndex; |
1029 |
|
1030 |
while (subgroupAttrs[indx]) { |
1031 |
char **values; |
1032 |
int val_index = 0; |
1033 |
|
1034 |
/* Get *all* matching "member" values from this group. */ |
1035 |
values = ldap_get_values(ldc->ldap, entry, subgroupAttrs[indx]); |
1036 |
|
1037 |
if (values) { |
1038 |
val_index = 0; |
1039 |
/* |
1040 |
* Now we are going to pare the subgroup members of this group to *just* |
1041 |
* the subgroups, add them to the compare_nodep, and then proceed to check |
1042 |
* the new level of subgroups. |
1043 |
*/ |
1044 |
while (values[val_index]) { |
1045 |
/* Check if this entry really is a group. */ |
1046 |
tmp_sgcIndex = 0; |
1047 |
result = LDAP_COMPARE_FALSE; |
1048 |
while ((tmp_sgcIndex < subgroupclasses->nelts) && (result != LDAP_COMPARE_TRUE)) { |
1049 |
result = uldap_cache_compare(r, ldc, url, values[val_index], "objectClass", |
1050 |
sgc_ents[tmp_sgcIndex].name); |
1051 |
|
1052 |
if (result != LDAP_COMPARE_TRUE) { |
1053 |
tmp_sgcIndex++; |
1054 |
} |
1055 |
} |
1056 |
/* It's a group, so add it to the array. */ |
1057 |
if (result == LDAP_COMPARE_TRUE) { |
1058 |
char **newgrp = (char **) apr_array_push(subgroups); |
1059 |
*newgrp = apr_pstrdup(r->pool, values[val_index]); |
1060 |
} |
1061 |
val_index++; |
1062 |
} |
1063 |
ldap_value_free(values); |
1064 |
} |
1065 |
indx++; |
1066 |
} |
1067 |
} |
1068 |
|
1069 |
ldap_msgfree(sga_res); |
1070 |
|
1071 |
if (subgroups->nelts > 0) { |
1072 |
/* We need to fill in tmp_local_subgroups using the data from LDAP */ |
1073 |
int sgindex; |
1074 |
char **group; |
1075 |
tmp_local_sgl = apr_pcalloc(r->pool, sizeof(util_compare_subgroup_t)); |
1076 |
tmp_local_sgl->subgroupDNs = apr_pcalloc(r->pool, sizeof(char *) * (subgroups->nelts)); |
1077 |
for (sgindex = 0; (group = apr_array_pop(subgroups)); sgindex++) { |
1078 |
tmp_local_sgl->subgroupDNs[sgindex] = apr_pstrdup(r->pool, *group); |
1079 |
} |
1080 |
tmp_local_sgl->len = sgindex; |
1081 |
} |
1082 |
|
1083 |
/* Find the generic group cache entry and add the sgl. */ |
1084 |
LDAP_CACHE_LOCK(); |
1085 |
|
1086 |
the_compare_node.dn = (char *)dn; |
1087 |
the_compare_node.attrib = (char *)"objectClass"; |
1088 |
the_compare_node.value = (char *)sgc_ents[base_sgcIndex].name; |
1089 |
the_compare_node.result = 0; |
1090 |
the_compare_node.sgl_processed = 0; |
1091 |
the_compare_node.subgroupList = NULL; |
1092 |
|
1093 |
compare_nodep = util_ald_cache_fetch(curl->compare_cache, &the_compare_node); |
1094 |
|
1095 |
if (compare_nodep == NULL) { |
1096 |
/* Didn't find it. This shouldn't happen since we just called uldap_cache_compare. */ |
1097 |
LDAP_CACHE_UNLOCK(); |
1098 |
ldc->reason = "check_subgroups failed to find the cache entry to add sub-group list to."; |
1099 |
return LDAP_COMPARE_FALSE; |
1100 |
} |
1101 |
else { |
1102 |
/* overwrite SGL if it was previously updated between the last |
1103 |
** two times we looked at the cache |
1104 |
*/ |
1105 |
compare_nodep->sgl_processed = 1; |
1106 |
if (tmp_local_sgl) { |
1107 |
compare_nodep->subgroupList = util_ald_sgl_dup(curl->compare_cache, tmp_local_sgl); |
1108 |
} |
1109 |
else { |
1110 |
/* We didn't find a single subgroup, next time save us from looking */ |
1111 |
compare_nodep->subgroupList = NULL; |
1112 |
} |
1113 |
} |
1114 |
/* unlock this read lock */ |
1115 |
LDAP_CACHE_UNLOCK(); |
1116 |
} |
1117 |
|
1118 |
/* tmp_local_sgl has either been created, or copied out of the cache */ |
1119 |
/* If tmp_local_sgl is NULL, there are no subgroups to process and we'll return false */ |
1120 |
result = LDAP_COMPARE_FALSE; |
1121 |
if (tmp_local_sgl) { |
1122 |
int sgindex = 0; |
1123 |
const char *group = NULL; |
1124 |
while ((result != LDAP_COMPARE_TRUE) && (sgindex < tmp_local_sgl->len)) { |
1125 |
group = tmp_local_sgl->subgroupDNs[sgindex]; |
1126 |
/* 4. Now loop through the subgroupList and call uldap_cache_compare to check for the user. */ |
1127 |
result = uldap_cache_compare(r, ldc, url, group, attrib, value); |
1128 |
if (result == LDAP_COMPARE_TRUE) { |
1129 |
/* 4.A. We found the user in the subgroup. Return LDAP_COMPARE_TRUE. */ |
1130 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "[%" APR_PID_T_FMT "] util_ldap:" |
1131 |
" Found the user in a subgroup (%s) at level %d of %d. (7).", |
1132 |
getpid(), group, cur_subgroup_depth+1, max_subgroup_depth); |
1133 |
} |
1134 |
else { |
1135 |
/* 4.B. We didn't find the user in this subgroup, so recurse into it and keep looking. */ |
1136 |
result = uldap_cache_check_subgroups(r, ldc, url, group, attrib, |
1137 |
value, subgroupAttrs, subgroupclasses, |
1138 |
cur_subgroup_depth+1, max_subgroup_depth); |
1139 |
} |
1140 |
sgindex++; |
1141 |
} |
1142 |
} |
1143 |
} |
1144 |
|
1145 |
return result; |
1146 |
} |
1147 |
|
1148 |
|
852 |
static int uldap_cache_checkuserid(request_rec *r, util_ldap_connection_t *ldc, |
1149 |
static int uldap_cache_checkuserid(request_rec *r, util_ldap_connection_t *ldc, |
853 |
const char *url, const char *basedn, |
1150 |
const char *url, const char *basedn, |
854 |
int scope, char **attrs, const char *filter, |
1151 |
int scope, char **attrs, const char *filter, |
Lines 2106-2111
Link Here
|
2106 |
APR_REGISTER_OPTIONAL_FN(uldap_cache_checkuserid); |
2403 |
APR_REGISTER_OPTIONAL_FN(uldap_cache_checkuserid); |
2107 |
APR_REGISTER_OPTIONAL_FN(uldap_cache_getuserdn); |
2404 |
APR_REGISTER_OPTIONAL_FN(uldap_cache_getuserdn); |
2108 |
APR_REGISTER_OPTIONAL_FN(uldap_ssl_supported); |
2405 |
APR_REGISTER_OPTIONAL_FN(uldap_ssl_supported); |
|
|
2406 |
APR_REGISTER_OPTIONAL_FN(uldap_cache_check_subgroups); |
2109 |
|
2407 |
|
2110 |
ap_hook_post_config(util_ldap_post_config,NULL,NULL,APR_HOOK_MIDDLE); |
2408 |
ap_hook_post_config(util_ldap_post_config,NULL,NULL,APR_HOOK_MIDDLE); |
2111 |
ap_hook_handler(util_ldap_handler, NULL, NULL, APR_HOOK_MIDDLE); |
2409 |
ap_hook_handler(util_ldap_handler, NULL, NULL, APR_HOOK_MIDDLE); |