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