]>
Commit | Line | Data |
---|---|---|
8f7b71f7 | 1 | /* |
2 | * squid_ldap_match: lookup group membership in LDAP | |
3 | * | |
4 | * Author: Flavio Pescuma <flavio@marasystems.com> | |
5 | * MARA Systems AB, Sweden | |
6 | * | |
7 | * Based on squid_ldap_auth by Glen Newton | |
8 | * | |
9 | * Dependencies: You need to get the OpenLDAP libraries | |
10 | * from http://www.openldap.org | |
11 | * | |
12 | * License: squid_ldap_match is free software; you can redistribute it | |
13 | * and/or modify it under the terms of the GNU General Public License | |
14 | * as published by the Free Software Foundation; either version 2, | |
15 | * or (at your option) any later version. | |
16 | * | |
17 | * Changes: | |
18 | * Version 2.0 | |
19 | * 2002-01-22: Henrik Nordstrom <hno@marasystems.com> | |
20 | * Added optional third query argument for search RDN | |
21 | * 2002-01-22: Henrik Nordstrom <hno@marasystems.com> | |
22 | * Removed unused options, and fully changed name | |
23 | * to squid_ldap_match. | |
24 | * Version 1.0 | |
25 | * 2001-07-17: Flavio Pescuma <flavio@marasystems.com> | |
26 | * Using the main function from squid_ldap_auth | |
27 | * wrote squid_ldap_match. This program replaces | |
28 | * the %a and %v (ldapfilter.conf) from the filter | |
29 | * template supplied with -f with the two arguments | |
30 | * sent by squid. Returns OK if the ldap_search | |
31 | * using the composed filter succeeds. | |
32 | * | |
33 | * OLD Change: (from squid_ldap_auth.c) | |
34 | * 2001-05-02: Henrik Nordstrom <hno@squid-cache.org> | |
35 | * - Support newer OpenLDAP 2.x libraries using the | |
36 | * revised Internet Draft API which unfortunately | |
37 | * is not backwards compatible with RFC1823.. | |
38 | * 2001-04-15: Henrik Nordstrom <hno@squid-cache.org> | |
39 | * - Added command line option for basedn | |
40 | * - Added the ability to search for the user DN | |
41 | * 2001-04-16: Henrik Nordstrom <hno@squid-cache.org> | |
42 | * - Added -D binddn -w bindpasswd. | |
43 | * 2001-04-17: Henrik Nordstrom <hno@squid-cache.org> | |
44 | * - Added -R to disable referrals | |
45 | * - Added -a to control alias dereferencing | |
46 | * 2001-04-17: Henrik Nordstrom <hno@squid-cache.org> | |
47 | * - Added -u, DN username attribute name | |
48 | * 2001-04-18: Henrik Nordstrom <hno@squid-cache.org> | |
49 | * - Allow full filter specifications in -f | |
50 | */ | |
51 | ||
52 | #include <stdio.h> | |
53 | #include <string.h> | |
54 | #include <stdlib.h> | |
55 | #include <lber.h> | |
56 | #include <ldap_cdefs.h> | |
57 | #include <ldap.h> | |
58 | ||
59 | /* Change this to your search base */ | |
60 | static char *basedn; | |
61 | static char *searchfilter = NULL; | |
62 | static char *binddn = NULL; | |
63 | static char *bindpasswd = NULL; | |
64 | static int searchscope = LDAP_SCOPE_SUBTREE; | |
65 | static int persistent = 0; | |
66 | static int noreferrals = 0; | |
67 | static int debug = 0; | |
68 | static int aliasderef = LDAP_DEREF_NEVER; | |
69 | ||
70 | static int searchLDAP(LDAP * ld, char *group, char *user, char *grouprdn); | |
71 | ||
72 | /* Yuck.. we need to glue to different versions of the API */ | |
73 | ||
74 | #if defined(LDAP_API_VERSION) && LDAP_API_VERSION > 1823 | |
75 | static int squid_ldap_errno(LDAP *ld) | |
76 | { | |
77 | int err = 0; | |
78 | ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err); | |
79 | return err; | |
80 | } | |
81 | static void squid_ldap_set_aliasderef(LDAP *ld, int deref) | |
82 | { | |
83 | ldap_set_option(ld, LDAP_OPT_DEREF, &deref); | |
84 | } | |
85 | static void squid_ldap_set_referrals(LDAP *ld, int referrals) | |
86 | { | |
87 | int *value = referrals ? LDAP_OPT_ON : LDAP_OPT_OFF; | |
88 | ldap_set_option(ld, LDAP_OPT_REFERRALS, value); | |
89 | } | |
90 | #else | |
91 | static int squid_ldap_errno(LDAP *ld) | |
92 | { | |
93 | return ld->ld_errno; | |
94 | } | |
95 | static void squid_ldap_set_aliasderef(LDAP *ld, int deref) | |
96 | { | |
97 | ld->ld_deref = deref; | |
98 | } | |
99 | static void squid_ldap_set_referrals(LDAP *ld, int referrals) | |
100 | { | |
101 | if (referrals) | |
102 | ld->ld_options |= ~LDAP_OPT_REFERRALS; | |
103 | else | |
104 | ld->ld_options &= ~LDAP_OPT_REFERRALS; | |
105 | } | |
106 | #endif | |
107 | ||
108 | int | |
109 | main(int argc, char **argv) | |
110 | { | |
111 | char buf[256]; | |
112 | char *user, *group, *grouprdn; | |
113 | char *ldapServer; | |
114 | LDAP *ld = NULL; | |
115 | int tryagain,rc; | |
116 | ||
117 | setbuf(stdout, NULL); | |
118 | ||
119 | while (argc > 2 && argv[1][0] == '-') { | |
120 | char *value = ""; | |
121 | char option = argv[1][1]; | |
122 | switch(option) { | |
123 | case 'p': | |
124 | case 'R': | |
125 | break; | |
126 | default: | |
127 | if (strlen(argv[1]) > 2) { | |
128 | value = argv[1]+2; | |
129 | } else { | |
130 | value = argv[2]; | |
131 | argv++; | |
132 | argc--; | |
133 | } | |
134 | break; | |
135 | } | |
136 | argv++; | |
137 | argc--; | |
138 | switch(option) { | |
139 | case 'b': | |
140 | basedn = value; | |
141 | break; | |
142 | case 'f': | |
143 | searchfilter = value; | |
144 | break; | |
145 | case 's': | |
146 | if (strcmp(value, "base") == 0) | |
147 | searchscope = LDAP_SCOPE_BASE; | |
148 | else if (strcmp(value, "one") == 0) | |
149 | searchscope = LDAP_SCOPE_ONELEVEL; | |
150 | else if (strcmp(value, "sub") == 0) | |
151 | searchscope = LDAP_SCOPE_SUBTREE; | |
152 | else { | |
153 | fprintf(stderr, "squid_ldap_match: ERROR: Unknown search scope '%s'\n", value); | |
154 | exit(1); | |
155 | } | |
156 | break; | |
157 | case 'a': | |
158 | if (strcmp(value, "never") == 0) | |
159 | aliasderef = LDAP_DEREF_NEVER; | |
160 | else if (strcmp(value, "always") == 0) | |
161 | aliasderef = LDAP_DEREF_ALWAYS; | |
162 | else if (strcmp(value, "search") == 0) | |
163 | aliasderef = LDAP_DEREF_SEARCHING; | |
164 | else if (strcmp(value, "find") == 0) | |
165 | aliasderef = LDAP_DEREF_FINDING; | |
166 | else { | |
167 | fprintf(stderr, "squid_ldap_match: ERROR: Unknown alias dereference method '%s'\n", value); | |
168 | exit(1); | |
169 | } | |
170 | break; | |
171 | case 'D': | |
172 | binddn = value; | |
173 | break; | |
174 | case 'w': | |
175 | bindpasswd = value; | |
176 | break; | |
177 | case 'p': | |
178 | persistent = !persistent; | |
179 | break; | |
180 | case 'R': | |
181 | noreferrals = !noreferrals; | |
182 | break; | |
183 | case 'd': | |
184 | debug = 1; | |
185 | break; | |
186 | default: | |
187 | fprintf(stderr, "squid_ldap_match: ERROR: Unknown command line option '%c'\n", option); | |
188 | exit(1); | |
189 | } | |
190 | } | |
191 | ||
192 | if (!basedn || !searchfilter || argc != 2) { | |
193 | fprintf(stderr, "Usage: squid_ldap_match [options] ldap_server_name\n\n"); | |
194 | fprintf(stderr, "\t-b basedn (REQUIRED)\tbase dn under where to search\n"); | |
195 | fprintf(stderr, "\t-f filter (REQUIRED)\tsearch filter pattern\n"); | |
196 | fprintf(stderr, "\t-s base|one|sub\t\tsearch scope\n"); | |
197 | fprintf(stderr, "\t-D binddn\t\tDN to bind as to perform searches\n"); | |
198 | fprintf(stderr, "\t-w bindpasswd\t\tpassword for binddn\n"); | |
199 | fprintf(stderr, "\t-p\t\t\tpersistent LDAP connection\n"); | |
200 | fprintf(stderr, "\t-R\t\t\tdo not follow referrals\n"); | |
201 | fprintf(stderr, "\t-a never|always|search|find\n\t\t\t\twhen to dereference aliases\n"); | |
202 | fprintf(stderr, "\n"); | |
203 | fprintf(stderr, "\tIf you need to bind as a user to perform searches then use the\n\t-D binddn -w bindpasswd options\n\n"); | |
204 | exit(1); | |
205 | } | |
206 | ||
207 | ldapServer = (char *) argv[1]; | |
208 | ||
209 | while (fgets(buf, 256, stdin) != NULL) { | |
210 | user = strtok(buf, " \n\r"); | |
211 | group = strtok(NULL, " \n\r"); | |
212 | grouprdn = strtok(NULL, " \n\r"); | |
213 | ||
214 | if (!user || !group) { | |
215 | printf("ERR\n"); | |
216 | continue; | |
217 | } | |
218 | ||
219 | tryagain = 1; | |
220 | recover: | |
221 | if (ld == NULL) { | |
222 | if ((ld = ldap_init(ldapServer, LDAP_PORT)) == NULL) { | |
223 | fprintf(stderr, "\nUnable to connect to LDAP server:%s port:%d\n", | |
224 | ldapServer, LDAP_PORT); | |
225 | exit(1); | |
226 | } | |
227 | squid_ldap_set_referrals(ld, !noreferrals); | |
228 | squid_ldap_set_aliasderef(ld, aliasderef); | |
229 | } | |
230 | rc = ldap_simple_bind_s(ld, binddn, bindpasswd); | |
231 | if (rc != LDAP_SUCCESS) { | |
232 | fprintf(stderr, "squid_ldap_match: WARNING, could not bind to binddn '%s'\n", ldap_err2string(rc)); | |
233 | exit(1); | |
234 | } | |
235 | if (debug) printf("Binding OK\n"); | |
236 | if (searchLDAP(ld, group, user, grouprdn) != 0) { | |
237 | if (tryagain) { | |
238 | tryagain = 0; | |
239 | ldap_unbind(ld); | |
240 | ld = NULL; | |
241 | goto recover; | |
242 | } | |
243 | printf("ERR\n"); | |
244 | } else { | |
245 | printf("OK\n"); | |
246 | } | |
247 | if (!persistent || (squid_ldap_errno(ld) != LDAP_SUCCESS && squid_ldap_errno(ld) != LDAP_INVALID_CREDENTIALS)) { | |
248 | ldap_unbind(ld); | |
249 | ld = NULL; | |
250 | } | |
251 | } | |
252 | if (ld) | |
253 | ldap_unbind(ld); | |
254 | return 0; | |
255 | } | |
256 | ||
257 | static int | |
258 | searchLDAP(LDAP * ld, char *group, char *member, char *grouprdn) | |
259 | { | |
260 | int rc; | |
261 | char filter[256]; | |
262 | static char searchbase[256]; | |
263 | LDAPMessage *res = NULL; | |
264 | LDAPMessage *entry; | |
265 | ||
266 | if (grouprdn) | |
267 | snprintf(searchbase, sizeof(searchbase), "%s,%s", grouprdn, basedn); | |
268 | else | |
269 | snprintf(searchbase, sizeof(searchbase), "%s", basedn); | |
270 | ||
271 | ldap_build_filter( filter, sizeof(filter), searchfilter, NULL, NULL, group, member, NULL ); | |
272 | if (debug) printf("filter %s\n",filter); | |
273 | ||
274 | ||
275 | if (ldap_search_s(ld, searchbase , searchscope, filter, NULL, 1, &res) != LDAP_SUCCESS) { | |
276 | int rc = ldap_result2error(ld, res, 0); | |
277 | if (noreferrals && rc == LDAP_PARTIAL_RESULTS) { | |
278 | /* Everything is fine. This is expected when referrals | |
279 | * are disabled. | |
280 | */ | |
281 | } else { | |
282 | fprintf(stderr, "squid_ldap_match: WARNING, LDAP search error '%s'\n", ldap_err2string(rc)); | |
283 | } | |
284 | ldap_msgfree(res); | |
285 | return 1; | |
286 | } | |
287 | entry = ldap_first_entry(ld, res); | |
288 | if (!entry) { | |
289 | ldap_msgfree(res); | |
290 | return 1; | |
291 | } | |
292 | ||
293 | ldap_msgfree(res); | |
294 | return 0; | |
295 | } |