kerberos_ldap_group.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 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"
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
49struct 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
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}
62#endif
63#endif /* HAVE_KRB5 */
64
65void
66init_args(struct main_args *margs)
67{
68 margs->nlist = nullptr;
69 margs->glist = nullptr;
70 margs->llist = nullptr;
71 margs->ulist = nullptr;
72 margs->tlist = nullptr;
73 margs->luser = nullptr;
74 margs->lpass = nullptr;
75 margs->lbind = nullptr;
76 margs->lurl = nullptr;
77 margs->ssl = nullptr;
78 margs->rc_allow = 0;
79 margs->AD = 0;
80 margs->mdepth = 5;
81 margs->nokerberos = 0;
82 margs->ddomain = nullptr;
83 margs->groups = nullptr;
84 margs->ndoms = nullptr;
85 margs->lservs = nullptr;
86 margs->principal = nullptr;
87}
88
89void clean_gd(struct gdstruct *gdsp);
90void clean_nd(struct ndstruct *ndsp);
91void clean_ls(struct lsstruct *lssp);
92
93void
94clean_gd(struct gdstruct *gdsp)
95{
96 struct gdstruct *p = nullptr, *pp = nullptr;
97
98 p = gdsp;
99 while (p) {
100 while (p->next) {
101 pp = p;
102 p = p->next;
103 }
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);
110 p = gdsp;
111 }
112}
113
114void
115clean_nd(struct ndstruct *ndsp)
116{
117 struct ndstruct *p = nullptr, *pp = nullptr;
118
119 p = ndsp;
120 while (p) {
121 while (p->next) {
122 pp = p;
123 p = p->next;
124 }
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);
131 p = ndsp;
132 }
133}
134
135void
136clean_ls(struct lsstruct *lssp)
137{
138 struct lsstruct *p = nullptr, *pp = nullptr;
139
140 p = lssp;
141 while (p) {
142 while (p->next) {
143 pp = p;
144 p = p->next;
145 }
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);
152 p = lssp;
153 }
154}
155
156void
157clean_args(struct main_args *margs)
158{
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);
170 if (margs->groups) {
171 clean_gd(margs->groups);
172 margs->groups = nullptr;
173 }
174 if (margs->ndoms) {
175 clean_nd(margs->ndoms);
176 margs->ndoms = nullptr;
177 }
178 if (margs->lservs) {
179 clean_ls(margs->lservs);
180 margs->lservs = nullptr;
181 }
182 safe_free(margs->principal);
183}
184
185void strup(char *s);
186
187int
188main(int argc, char *const argv[])
189{
190 char buf[6400];
191 char *user, *domain, *group;
192 char *up=nullptr, *dp=nullptr, *np=nullptr;
193 char *nuser, *nuser8 = nullptr, *netbios;
194 int opt;
195 struct main_args margs;
196#if HAVE_KRB5
197 krb5_error_code code = 0;
198
199 kparam.context = nullptr;
200#endif
201
202 setbuf(stdout, nullptr);
203 setbuf(stdin, nullptr);
204
205 init_args(&margs);
206
207 while (-1 != (opt = getopt(argc, argv, "diasng:D:N:P:S:u:U:t:T:p:l:b:m:h"))) {
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':
219 margs.ssl = xstrdup("yes");
220 break;
221 case 'n':
222 margs.nokerberos = 1;
223 break;
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;
233 case 'P':
234 margs.principal = xstrdup(optarg);
235 break;
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;
262 case 'S':
263 margs.llist = xstrdup(optarg);
264 break;
265 case 'h':
266 fprintf(stderr, "Usage: \n");
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");
268 fprintf(stderr, "-d full debug\n");
269 fprintf(stderr, "-i informational messages\n");
270 fprintf(stderr, "-n do not use Kerberos to authenticate to AD. Requires -u , -p and -l option\n");
271 fprintf(stderr, "-g group list\n");
272 fprintf(stderr, "-t group list (only group name hex UTF-8 format)\n");
273 fprintf(stderr, "-T group list (all in hex UTF-8 format - except separator @)\n");
274 fprintf(stderr, "-D default domain\n");
275 fprintf(stderr, "-N netbios to dns domain map\n");
276 fprintf(stderr, "-P service principal name to be used from keytab\n");
277 fprintf(stderr, "-S ldap server to dns domain map\n");
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");
294 fprintf(stderr, "group1@domain1:group2@domain2:group3@:group4 - A list is build with a colon as separator\n");
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");
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");
303 fprintf(stderr, "server1a@domain1:server1b@domain1:server2@domain2:server3@:server4 - A list is build with a colon as separator\n");
304 clean_args(&margs);
305 exit(EXIT_SUCCESS);
306 default:
307 warn((char *) "%s| %s: WARNING: unknown option: -%c.\n", LogTime(), PROGRAM, opt);
308 }
309 }
310
311 debug((char *) "%s| %s: INFO: Starting version %s\n", LogTime(), PROGRAM, KERBEROS_LDAP_GROUP_VERSION);
312 int gopt = 0;
313 if (create_gd(&margs)) {
314 if ( margs.glist != nullptr ) {
315 debug((char *) "%s| %s: FATAL: Error in group list: %s\n", LogTime(), PROGRAM, margs.glist ? margs.glist : "NULL");
316 SEND_BH("");
317 clean_args(&margs);
318 exit(EXIT_FAILURE);
319 } else {
320 debug((char *) "%s| %s: INFO: no group list given expect it from stdin\n", LogTime(), PROGRAM);
321 gopt = 1;
322 }
323 }
324 if (create_nd(&margs)) {
325 debug((char *) "%s| %s: FATAL: Error in netbios list: %s\n", LogTime(), PROGRAM, margs.nlist ? margs.nlist : "NULL");
326 SEND_BH("");
327 clean_args(&margs);
328 exit(EXIT_FAILURE);
329 }
330 if (create_ls(&margs)) {
331 debug((char *) "%s| %s: Error in ldap server list: %s\n", LogTime(), PROGRAM, margs.llist ? margs.llist : "NULL");
332 SEND_BH("");
333 clean_args(&margs);
334 exit(EXIT_FAILURE);
335 }
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]=nullptr;
345 kparam.cc[i]=nullptr;
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);
352 exit(EXIT_FAILURE);
353 }
354#endif
355
356 while (1) {
357 char *c;
358 if (fgets(buf, sizeof(buf) - 1, stdin) == nullptr) {
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)));
362
363 SEND_BH(strerror(ferror(stdin)));
364 clean_args(&margs);
365#if HAVE_KRB5
366 krb5_cleanup();
367#endif
368 exit(EXIT_FAILURE); /* BIIG buffer */
369 }
370 SEND_BH("fgets NULL");
371 clean_args(&margs);
372#if HAVE_KRB5
373 krb5_cleanup();
374#endif
375 exit(EXIT_SUCCESS);
376 }
377 c = (char *) memchr(buf, '\n', sizeof(buf) - 1);
378 if (c) {
379 *c = '\0';
380 } else {
381 SEND_BH("Invalid input. CR missing");
382 debug((char *) "%s| %s: ERR\n", LogTime(), PROGRAM);
383 continue;
384 }
385
386 user = strtok(buf, " \n");
387 if (!user) {
388 debug((char *) "%s| %s: INFO: No Username given\n", LogTime(), PROGRAM);
389 SEND_BH("Invalid request. No Username");
390 continue;
391 }
392 rfc1738_unescape(user);
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';
402 ++nuser;
403 } else {
404 *nuser8 = '\0';
405 nuser = nuser8 + 3;
406 }
407 netbios = user;
408 up = xstrdup(rfc1738_escape(nuser));
409 np = xstrdup(rfc1738_escape(netbios));
410 if (debug_enabled)
411 debug((char *) "%s| %s: INFO: Got User: %s Netbios Name: %s\n", LogTime(), PROGRAM, up, np);
412 else
413 log((char *) "%s| %s: INFO: Got User: %s Netbios Name: %s\n", LogTime(), PROGRAM, up, np);
414 domain = get_netbios_name(&margs, netbios);
415 user = nuser;
416 safe_free(up);
417 safe_free(np);
418 } else if (domain) {
419 strup(domain);
420 *domain = '\0';
421 ++domain;
422 }
423 up = xstrdup(rfc1738_escape(user));
424 if (domain)
425 dp = xstrdup(rfc1738_escape(domain));
426 if (!domain && margs.ddomain) {
427 domain = xstrdup(margs.ddomain);
428 dp = xstrdup(rfc1738_escape(domain));
429 if (debug_enabled)
430 debug((char *) "%s| %s: INFO: Got User: %s set default domain: %s\n", LogTime(), PROGRAM, up, dp);
431 else
432 log((char *) "%s| %s: INFO: Got User: %s set default domain: %s\n", LogTime(), PROGRAM, up, dp);
433 }
434 if (debug_enabled)
435 debug((char *) "%s| %s: INFO: Got User: %s Domain: %s\n", LogTime(), PROGRAM, up, domain ? dp : "NULL");
436 else
437 log((char *) "%s| %s: INFO: Got User: %s Domain: %s\n", LogTime(), PROGRAM, up, domain ? dp : "NULL");
438
439 safe_free(up);
440 safe_free(dp);
441 if (!strcmp(user, "QQ") && domain && !strcmp(domain, "QQ")) {
442 clean_args(&margs);
443#if HAVE_KRB5
444 krb5_cleanup();
445#endif
446
447 exit(EXIT_SUCCESS);
448 }
449 if (gopt) {
450 if ((group = strtok(nullptr, " \n")) != nullptr) {
451 debug((char *) "%s| %s: INFO: Read group list %s from stdin\n", LogTime(), PROGRAM, group);
452 rfc1738_unescape(group);
453 if (margs.groups) {
454 clean_gd(margs.groups);
455 margs.groups = nullptr;
456 }
457 margs.glist = xstrdup(group);
458 if (create_gd(&margs)) {
459 SEND_BH("Error in group list");
460 debug((char *) "%s| %s: FATAL: Error in group list: %s\n", LogTime(), PROGRAM, margs.glist ? margs.glist : "NULL");
461 continue;
462 }
463 } else {
464 SEND_BH("No group list received on stdin");
465 debug((char *) "%s| %s: FATAL: No group list received on stdin\n", LogTime(), PROGRAM);
466 continue;
467 }
468 }
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 }
476 }
477
478}
479
480void
481strup(char *s)
482{
483 while (*s) {
484 *s = (char)toupper((unsigned char) *s);
485 ++s;
486 }
487}
488
489#else
490#include <cstdlib>
491int
493{
494 setbuf(stdout, nullptr);
495 setbuf(stdin, nullptr);
496 char buf[6400];
497 while (1) {
498 if (fgets(buf, sizeof(buf) - 1, stdin) == nullptr) {
499 }
500 fprintf(stdout, "ERR\n");
501 fprintf(stderr, "LDAP group authorisation not supported\n");
502 }
503 return EXIT_SUCCESS;
504}
505#endif
506
int create_gd(struct main_args *margs)
void log(char *format,...)
void error(char *format,...)
void warn(char *format,...)
#define KERBEROS_LDAP_GROUP_VERSION
Definition: support.h:33
#define PROGRAM
Definition: support.h:166
int create_nd(struct main_args *margs)
const char * LogTime(void)
void clean_args(struct main_args *margs)
SQUIDCEXTERN int log_enabled
Definition: support.h:93
int create_ls(struct main_args *margs)
char * get_netbios_name(struct main_args *margs, char *netbios)
int check_memberof(struct main_args *margs, char *user, char *domain)
void init_args(struct main_args *margs)
int debug_enabled
Definition: debug.cc:13
void debug(const char *format,...)
Definition: debug.cc:19
int getopt(int nargc, char *const *nargv, const char *ostr)
Definition: getopt.c:62
char * optarg
Definition: getopt.c:51
int main()
#define xstrdup
#define SEND_ERR(x)
#define SEND_OK(x)
#define SEND_BH(x)
#define rfc1738_escape(x)
Definition: rfc1738.h:52
void rfc1738_unescape(char *url)
Definition: rfc1738.c:146
int code
Definition: smb-errors.c:145
char * strerror(int ern)
Definition: strerror.c:22
struct gdstruct * next
Definition: support.h:58
char * group
Definition: support.h:56
char * domain
Definition: support.h:57
struct lsstruct * next
Definition: support.h:68
char * domain
Definition: support.h:67
char * lserver
Definition: support.h:66
char * ulist
Definition: support.h:73
struct lsstruct * lservs
Definition: support.h:89
struct ndstruct * ndoms
Definition: support.h:88
char * ddomain
Definition: support.h:86
char * ssl
Definition: support.h:81
char * nlist
Definition: support.h:75
char * glist
Definition: support.h:72
int AD
Definition: support.h:83
int mdepth
Definition: support.h:84
char * llist
Definition: support.h:76
int rc_allow
Definition: support.h:82
char * luser
Definition: support.h:77
char * lpass
Definition: support.h:78
char * principal
Definition: support.h:90
char * lurl
Definition: support.h:80
char * tlist
Definition: support.h:74
struct gdstruct * groups
Definition: support.h:87
char * lbind
Definition: support.h:79
int nokerberos
Definition: support.h:85
char * domain
Definition: support.h:62
char * netbios
Definition: support.h:61
struct ndstruct * next
Definition: support.h:63
#define safe_free(x)
Definition: xalloc.h:73

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors