]> git.ipfire.org Git - thirdparty/squid.git/blob - src/acl/external/kerberos_ldap_group/kerberos_ldap_group.cc
Docs: Copyright updates for 2018 (#114)
[thirdparty/squid.git] / src / acl / external / kerberos_ldap_group / kerberos_ldap_group.cc
1 /*
2 * Copyright (C) 1996-2018 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9 /*
10 * -----------------------------------------------------------------------------
11 *
12 * Author: Markus Moeller (markus_moeller at compuserve.com)
13 *
14 * Copyright (C) 2007 Markus Moeller. All rights reserved.
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
29 *
30 * As a special exemption, M Moeller gives permission to link this program
31 * with MIT, Heimdal or other GSS/Kerberos libraries, and distribute
32 * the resulting executable, without including the source code for
33 * the Libraries in the source distribution.
34 *
35 * -----------------------------------------------------------------------------
36 */
37
38 #include "squid.h"
39 #include "helper/protocol_defines.h"
40 #include "rfc1738.h"
41 #include "util.h"
42
43 #if HAVE_LDAP
44
45 #include "support.h"
46 #include <cctype>
47
48 #if HAVE_KRB5
49 struct kstruct kparam;
50
51 #if !HAVE_ERROR_MESSAGE && HAVE_KRB5_GET_ERROR_MESSAGE
52 #define error_message(code) krb5_get_error_message(kparam.context,code)
53 #elif !HAVE_ERROR_MESSAGE && HAVE_KRB5_GET_ERR_TEXT
54 #define error_message(code) krb5_get_err_text(kparam.context,code)
55 #elif !HAVE_ERROR_MESSAGE
56 static char err_code[17];
57 const char *KRB5_CALLCONV
58 error_message(long code) {
59 snprintf(err_code,16,"%ld",code);
60 return err_code;
61 }
62 #endif
63 #endif /* HAVE_KRB5 */
64
65 void
66 init_args(struct main_args *margs)
67 {
68 margs->nlist = NULL;
69 margs->glist = NULL;
70 margs->llist = NULL;
71 margs->ulist = NULL;
72 margs->tlist = NULL;
73 margs->luser = NULL;
74 margs->lpass = NULL;
75 margs->lbind = NULL;
76 margs->lurl = NULL;
77 margs->ssl = NULL;
78 margs->rc_allow = 0;
79 margs->AD = 0;
80 margs->mdepth = 5;
81 margs->nokerberos = 0;
82 margs->ddomain = NULL;
83 margs->groups = NULL;
84 margs->ndoms = NULL;
85 margs->lservs = NULL;
86 }
87
88 void clean_gd(struct gdstruct *gdsp);
89 void clean_nd(struct ndstruct *ndsp);
90 void clean_ls(struct lsstruct *lssp);
91
92 void
93 clean_gd(struct gdstruct *gdsp)
94 {
95 struct gdstruct *p = NULL, *pp = NULL;
96
97 p = gdsp;
98 while (p) {
99 while (p->next) {
100 pp = p;
101 p = p->next;
102 }
103 safe_free(p->group);
104 safe_free(p->domain);
105 if (pp)
106 safe_free(pp->next);
107 if (p == gdsp)
108 safe_free(gdsp);
109 p = gdsp;
110 }
111 }
112
113 void
114 clean_nd(struct ndstruct *ndsp)
115 {
116 struct ndstruct *p = NULL, *pp = NULL;
117
118 p = ndsp;
119 while (p) {
120 while (p->next) {
121 pp = p;
122 p = p->next;
123 }
124 safe_free(p->netbios);
125 safe_free(p->domain);
126 if (pp)
127 safe_free(pp->next);
128 if (p == ndsp)
129 safe_free(ndsp);
130 p = ndsp;
131 }
132 }
133
134 void
135 clean_ls(struct lsstruct *lssp)
136 {
137 struct lsstruct *p = NULL, *pp = NULL;
138
139 p = lssp;
140 while (p) {
141 while (p->next) {
142 pp = p;
143 p = p->next;
144 }
145 safe_free(p->lserver);
146 safe_free(p->domain);
147 if (pp)
148 safe_free(pp->next);
149 if (p == lssp)
150 safe_free(lssp);
151 p = lssp;
152 }
153 }
154
155 void
156 clean_args(struct main_args *margs)
157 {
158 safe_free(margs->glist);
159 safe_free(margs->ulist);
160 safe_free(margs->tlist);
161 safe_free(margs->nlist);
162 safe_free(margs->llist);
163 safe_free(margs->luser);
164 safe_free(margs->lpass);
165 safe_free(margs->lbind);
166 safe_free(margs->lurl);
167 safe_free(margs->ssl);
168 safe_free(margs->ddomain);
169 if (margs->groups) {
170 clean_gd(margs->groups);
171 margs->groups = NULL;
172 }
173 if (margs->ndoms) {
174 clean_nd(margs->ndoms);
175 margs->ndoms = NULL;
176 }
177 if (margs->lservs) {
178 clean_ls(margs->lservs);
179 margs->lservs = NULL;
180 }
181 }
182
183 void strup(char *s);
184
185 int
186 main(int argc, char *const argv[])
187 {
188 char buf[6400];
189 char *user, *domain, *group;
190 char *up=NULL, *dp=NULL, *np=NULL;
191 char *nuser, *nuser8 = NULL, *netbios;
192 int opt;
193 struct main_args margs;
194 #if HAVE_KRB5
195 krb5_error_code code = 0;
196
197 kparam.context = NULL;
198 #endif
199
200 setbuf(stdout, NULL);
201 setbuf(stdin, NULL);
202
203 init_args(&margs);
204
205 while (-1 != (opt = getopt(argc, argv, "diasng:D:N:S:u:U:t:T:p:l:b:m:h"))) {
206 switch (opt) {
207 case 'd':
208 debug_enabled = 1;
209 break;
210 case 'i':
211 log_enabled = 1;
212 break;
213 case 'a':
214 margs.rc_allow = 1;
215 break;
216 case 's':
217 margs.ssl = xstrdup("yes");
218 break;
219 case 'n':
220 margs.nokerberos = 1;
221 break;
222 case 'g':
223 margs.glist = xstrdup(optarg);
224 break;
225 case 'D':
226 margs.ddomain = xstrdup(optarg);
227 break;
228 case 'N':
229 margs.nlist = xstrdup(optarg);
230 break;
231 case 'u':
232 margs.luser = xstrdup(optarg);
233 break;
234 case 'U':
235 margs.ulist = xstrdup(optarg);
236 break;
237 case 't':
238 margs.ulist = xstrdup(optarg);
239 break;
240 case 'T':
241 margs.tlist = xstrdup(optarg);
242 break;
243 case 'p':
244 margs.lpass = xstrdup(optarg);
245 /* Hide Password */
246 memset(optarg, 'X', strlen(optarg));
247 break;
248 case 'l':
249 margs.lurl = xstrdup(optarg);
250 break;
251 case 'b':
252 margs.lbind = xstrdup(optarg);
253 break;
254 case 'm':
255 margs.mdepth = atoi(optarg);
256 break;
257 case 'S':
258 margs.llist = xstrdup(optarg);
259 break;
260 case 'h':
261 fprintf(stderr, "Usage: \n");
262 fprintf(stderr, "squid_kerb_ldap [-d] [-i] -g group list [-D domain] [-N netbios domain map] [-s] [-u ldap user] [-p ldap user password] [-l ldap url] [-b ldap bind path] [-a] [-m max depth] [-h]\n");
263 fprintf(stderr, "-d full debug\n");
264 fprintf(stderr, "-i informational messages\n");
265 fprintf(stderr, "-n do not use Kerberos to authenticate to AD. Requires -u , -p and -l option\n");
266 fprintf(stderr, "-g group list\n");
267 fprintf(stderr, "-t group list (only group name hex UTF-8 format)\n");
268 fprintf(stderr, "-T group list (all in hex UTF-8 format - except separator @)\n");
269 fprintf(stderr, "-D default domain\n");
270 fprintf(stderr, "-N netbios to dns domain map\n");
271 fprintf(stderr, "-S ldap server to dns domain map\n");
272 fprintf(stderr, "-u ldap user\n");
273 fprintf(stderr, "-p ldap user password\n");
274 fprintf(stderr, "-l ldap url\n");
275 fprintf(stderr, "-b ldap bind path\n");
276 fprintf(stderr, "-s use SSL encryption with Kerberos authentication\n");
277 fprintf(stderr, "-a allow SSL without cert verification\n");
278 fprintf(stderr, "-m maximal depth for recursive searches\n");
279 fprintf(stderr, "-h help\n");
280 fprintf(stderr, "The ldap url, ldap user and ldap user password details are only used if the kerberised\n");
281 fprintf(stderr, "access fails(e.g. unknown domain) or if the username does not contain a domain part\n");
282 fprintf(stderr, "and no default domain is provided.\n");
283 fprintf(stderr, "If the ldap url starts with ldaps:// it is either start_tls or simple SSL\n");
284 fprintf(stderr, "The group list can be:\n");
285 fprintf(stderr, "group - In this case group can be used for all keberised and non kerberised ldap servers\n");
286 fprintf(stderr, "group@ - In this case group can be used for all keberised ldap servers\n");
287 fprintf(stderr, "group@domain - In this case group can be used for ldap servers of domain domain\n");
288 fprintf(stderr, "group1@domain1:group2@domain2:group3@:group4 - A list is build with a colon as separator\n");
289 fprintf(stderr, "Group membership is determined with AD servers through the users memberof attribute which\n");
290 fprintf(stderr, "is followed to the top (e.g. if the group is a member of a group)\n");
291 fprintf(stderr, "Group membership is determined with non AD servers through the users memberuid (assuming\n");
292 fprintf(stderr, "PosixGroup) or primary group membership (assuming PosixAccount)\n");
293 fprintf(stderr, "The ldap server list can be:\n");
294 fprintf(stderr, "server - In this case server can be used for all Kerberos domains\n");
295 fprintf(stderr, "server@ - In this case server can be used for all Kerberos domains\n");
296 fprintf(stderr, "server@domain - In this case server can be used for Kerberos domain domain\n");
297 fprintf(stderr, "server1a@domain1:server1b@domain1:server2@domain2:server3@:server4 - A list is build with a colon as separator\n");
298 clean_args(&margs);
299 exit(EXIT_SUCCESS);
300 default:
301 warn((char *) "%s| %s: WARNING: unknown option: -%c.\n", LogTime(), PROGRAM, opt);
302 }
303 }
304
305 debug((char *) "%s| %s: INFO: Starting version %s\n", LogTime(), PROGRAM, KERBEROS_LDAP_GROUP_VERSION);
306 int gopt = 0;
307 if (create_gd(&margs)) {
308 if ( margs.glist != NULL ) {
309 debug((char *) "%s| %s: FATAL: Error in group list: %s\n", LogTime(), PROGRAM, margs.glist ? margs.glist : "NULL");
310 SEND_BH("");
311 clean_args(&margs);
312 exit(EXIT_FAILURE);
313 } else {
314 debug((char *) "%s| %s: INFO: no group list given expect it from stdin\n", LogTime(), PROGRAM);
315 gopt = 1;
316 }
317 }
318 if (create_nd(&margs)) {
319 debug((char *) "%s| %s: FATAL: Error in netbios list: %s\n", LogTime(), PROGRAM, margs.nlist ? margs.nlist : "NULL");
320 SEND_BH("");
321 clean_args(&margs);
322 exit(EXIT_FAILURE);
323 }
324 if (create_ls(&margs)) {
325 debug((char *) "%s| %s: Error in ldap server list: %s\n", LogTime(), PROGRAM, margs.llist ? margs.llist : "NULL");
326 SEND_BH("");
327 clean_args(&margs);
328 exit(EXIT_FAILURE);
329 }
330
331 #if HAVE_KRB5
332 /*
333 * Initialise Kerberos
334 */
335
336 code = krb5_init_context(&kparam.context);
337 for (int i=0; i<MAX_DOMAINS; i++) {
338 kparam.mem_ccache[i]=NULL;
339 kparam.cc[i]=NULL;
340 kparam.ncache=0;
341 }
342 if (code) {
343 error((char *) "%s| %s: ERROR: Error while initialising Kerberos library : %s\n", LogTime(), PROGRAM, error_message(code));
344 SEND_BH("");
345 clean_args(&margs);
346 exit(EXIT_FAILURE);
347 }
348 #endif
349
350 while (1) {
351 char *c;
352 if (fgets(buf, sizeof(buf) - 1, stdin) == NULL) {
353 if (ferror(stdin)) {
354 debug((char *) "%s| %s: FATAL: fgets() failed! dying..... errno=%d (%s)\n", LogTime(), PROGRAM, ferror(stdin),
355 strerror(ferror(stdin)));
356
357 SEND_BH(strerror(ferror(stdin)));
358 clean_args(&margs);
359 #if HAVE_KRB5
360 krb5_cleanup();
361 #endif
362 exit(EXIT_FAILURE); /* BIIG buffer */
363 }
364 SEND_BH("fgets NULL");
365 clean_args(&margs);
366 #if HAVE_KRB5
367 krb5_cleanup();
368 #endif
369 exit(EXIT_SUCCESS);
370 }
371 c = (char *) memchr(buf, '\n', sizeof(buf) - 1);
372 if (c) {
373 *c = '\0';
374 } else {
375 SEND_BH("Invalid input. CR missing");
376 debug((char *) "%s| %s: ERR\n", LogTime(), PROGRAM);
377 continue;
378 }
379
380 user = strtok(buf, " \n");
381 if (!user) {
382 debug((char *) "%s| %s: INFO: No Username given\n", LogTime(), PROGRAM);
383 SEND_BH("Invalid request. No Username");
384 continue;
385 }
386 rfc1738_unescape(user);
387 nuser = strchr(user, '\\');
388 if (!nuser)
389 nuser8 = strstr(user, "%5C");
390 if (!nuser && !nuser8)
391 nuser8 = strstr(user, "%5c");
392 domain = strrchr(user, '@');
393 if (nuser || nuser8) {
394 if (nuser) {
395 *nuser = '\0';
396 ++nuser;
397 } else {
398 *nuser8 = '\0';
399 nuser = nuser8 + 3;
400 }
401 netbios = user;
402 up = xstrdup(rfc1738_escape(nuser));
403 np = xstrdup(rfc1738_escape(netbios));
404 if (debug_enabled)
405 debug((char *) "%s| %s: INFO: Got User: %s Netbios Name: %s\n", LogTime(), PROGRAM, up, np);
406 else
407 log((char *) "%s| %s: INFO: Got User: %s Netbios Name: %s\n", LogTime(), PROGRAM, up, np);
408 domain = get_netbios_name(&margs, netbios);
409 user = nuser;
410 safe_free(up);
411 safe_free(np);
412 } else if (domain) {
413 strup(domain);
414 *domain = '\0';
415 ++domain;
416 }
417 up = xstrdup(rfc1738_escape(user));
418 if (domain)
419 dp = xstrdup(rfc1738_escape(domain));
420 if (!domain && margs.ddomain) {
421 domain = xstrdup(margs.ddomain);
422 dp = xstrdup(rfc1738_escape(domain));
423 if (debug_enabled)
424 debug((char *) "%s| %s: INFO: Got User: %s set default domain: %s\n", LogTime(), PROGRAM, up, dp);
425 else
426 log((char *) "%s| %s: INFO: Got User: %s set default domain: %s\n", LogTime(), PROGRAM, up, dp);
427 }
428 if (debug_enabled)
429 debug((char *) "%s| %s: INFO: Got User: %s Domain: %s\n", LogTime(), PROGRAM, up, domain ? dp : "NULL");
430 else
431 log((char *) "%s| %s: INFO: Got User: %s Domain: %s\n", LogTime(), PROGRAM, up, domain ? dp : "NULL");
432
433 safe_free(up);
434 safe_free(dp);
435 if (!strcmp(user, "QQ") && domain && !strcmp(domain, "QQ")) {
436 clean_args(&margs);
437 #if HAVE_KRB5
438 krb5_cleanup();
439 #endif
440
441 exit(EXIT_SUCCESS);
442 }
443 if (gopt) {
444 if ((group = strtok(NULL, " \n")) != NULL) {
445 debug((char *) "%s| %s: INFO: Read group list %s from stdin\n", LogTime(), PROGRAM, group);
446 rfc1738_unescape(group);
447 if (margs.groups) {
448 clean_gd(margs.groups);
449 margs.groups = NULL;
450 }
451 margs.glist = xstrdup(group);
452 if (create_gd(&margs)) {
453 SEND_BH("Error in group list");
454 debug((char *) "%s| %s: FATAL: Error in group list: %s\n", LogTime(), PROGRAM, margs.glist ? margs.glist : "NULL");
455 continue;
456 }
457 } else {
458 SEND_BH("No group list received on stdin");
459 debug((char *) "%s| %s: FATAL: No group list received on stdin\n", LogTime(), PROGRAM);
460 continue;
461 }
462 }
463 if (check_memberof(&margs, user, domain)) {
464 SEND_OK("");
465 debug((char *) "%s| %s: DEBUG: OK\n", LogTime(), PROGRAM);
466 } else {
467 SEND_ERR("");
468 debug((char *) "%s| %s: DEBUG: ERR\n", LogTime(), PROGRAM);
469 }
470 }
471
472 }
473
474 void
475 strup(char *s)
476 {
477 while (*s) {
478 *s = (char)toupper((unsigned char) *s);
479 ++s;
480 }
481 }
482
483 #else
484 #include <cstdlib>
485 int
486 main(int argc, char *const argv[])
487 {
488 setbuf(stdout, NULL);
489 setbuf(stdin, NULL);
490 char buf[6400];
491 while (1) {
492 if (fgets(buf, sizeof(buf) - 1, stdin) == NULL) {
493 }
494 fprintf(stdout, "ERR\n");
495 fprintf(stderr, "LDAP group authorisation not supported\n");
496 }
497 return EXIT_SUCCESS;
498 }
499 #endif
500