2 * Copyright (C) 1996-2020 The Squid Software Foundation and contributors
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.
10 * -----------------------------------------------------------------------------
12 * Author: Markus Moeller (markus_moeller at compuserve.com)
14 * Copyright (C) 2007 Markus Moeller. All rights reserved.
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.
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.
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.
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.
35 * -----------------------------------------------------------------------------
39 #include "helper/protocol_defines.h"
49 struct kstruct kparam
;
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
);
63 #endif /* HAVE_KRB5 */
66 init_args(struct main_args
*margs
)
81 margs
->nokerberos
= 0;
82 margs
->ddomain
= NULL
;
86 margs
->principal
= NULL
;
89 void clean_gd(struct gdstruct
*gdsp
);
90 void clean_nd(struct ndstruct
*ndsp
);
91 void clean_ls(struct lsstruct
*lssp
);
94 clean_gd(struct gdstruct
*gdsp
)
96 struct gdstruct
*p
= NULL
, *pp
= NULL
;
105 safe_free(p
->domain
);
115 clean_nd(struct ndstruct
*ndsp
)
117 struct ndstruct
*p
= NULL
, *pp
= NULL
;
125 safe_free(p
->netbios
);
126 safe_free(p
->domain
);
136 clean_ls(struct lsstruct
*lssp
)
138 struct lsstruct
*p
= NULL
, *pp
= NULL
;
146 safe_free(p
->lserver
);
147 safe_free(p
->domain
);
157 clean_args(struct main_args
*margs
)
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
);
171 clean_gd(margs
->groups
);
172 margs
->groups
= NULL
;
175 clean_nd(margs
->ndoms
);
179 clean_ls(margs
->lservs
);
180 margs
->lservs
= NULL
;
182 safe_free(margs
->principal
);
188 main(int argc
, char *const argv
[])
191 char *user
, *domain
, *group
;
192 char *up
=NULL
, *dp
=NULL
, *np
=NULL
;
193 char *nuser
, *nuser8
= NULL
, *netbios
;
195 struct main_args margs
;
197 krb5_error_code code
= 0;
199 kparam
.context
= NULL
;
202 setbuf(stdout
, NULL
);
207 while (-1 != (opt
= getopt(argc
, argv
, "diasng:D:N:P:S:u:U:t:T:p:l:b:m:h"))) {
219 margs
.ssl
= xstrdup("yes");
222 margs
.nokerberos
= 1;
225 margs
.glist
= xstrdup(optarg
);
228 margs
.ddomain
= xstrdup(optarg
);
231 margs
.nlist
= xstrdup(optarg
);
234 margs
.principal
= xstrdup(optarg
);
237 margs
.luser
= xstrdup(optarg
);
240 margs
.ulist
= xstrdup(optarg
);
243 margs
.ulist
= xstrdup(optarg
);
246 margs
.tlist
= xstrdup(optarg
);
249 margs
.lpass
= xstrdup(optarg
);
251 memset(optarg
, 'X', strlen(optarg
));
254 margs
.lurl
= xstrdup(optarg
);
257 margs
.lbind
= xstrdup(optarg
);
260 margs
.mdepth
= atoi(optarg
);
263 margs
.llist
= xstrdup(optarg
);
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");
307 warn((char *) "%s| %s: WARNING: unknown option: -%c.\n", LogTime(), PROGRAM
, opt
);
311 debug((char *) "%s| %s: INFO: Starting version %s\n", LogTime(), PROGRAM
, KERBEROS_LDAP_GROUP_VERSION
);
313 if (create_gd(&margs
)) {
314 if ( margs
.glist
!= NULL
) {
315 debug((char *) "%s| %s: FATAL: Error in group list: %s\n", LogTime(), PROGRAM
, margs
.glist
? margs
.glist
: "NULL");
320 debug((char *) "%s| %s: INFO: no group list given expect it from stdin\n", LogTime(), PROGRAM
);
324 if (create_nd(&margs
)) {
325 debug((char *) "%s| %s: FATAL: Error in netbios list: %s\n", LogTime(), PROGRAM
, margs
.nlist
? margs
.nlist
: "NULL");
330 if (create_ls(&margs
)) {
331 debug((char *) "%s| %s: Error in ldap server list: %s\n", LogTime(), PROGRAM
, margs
.llist
? margs
.llist
: "NULL");
339 * Initialise Kerberos
342 code
= krb5_init_context(&kparam
.context
);
343 for (int i
=0; i
<MAX_DOMAINS
; i
++) {
344 kparam
.mem_ccache
[i
]=NULL
;
349 error((char *) "%s| %s: ERROR: Error while initialising Kerberos library : %s\n", LogTime(), PROGRAM
, error_message(code
));
358 if (fgets(buf
, sizeof(buf
) - 1, stdin
) == NULL
) {
360 debug((char *) "%s| %s: FATAL: fgets() failed! dying..... errno=%d (%s)\n", LogTime(), PROGRAM
, ferror(stdin
),
361 strerror(ferror(stdin
)));
363 SEND_BH(strerror(ferror(stdin
)));
368 exit(EXIT_FAILURE
); /* BIIG buffer */
370 SEND_BH("fgets NULL");
377 c
= (char *) memchr(buf
, '\n', sizeof(buf
) - 1);
381 SEND_BH("Invalid input. CR missing");
382 debug((char *) "%s| %s: ERR\n", LogTime(), PROGRAM
);
386 user
= strtok(buf
, " \n");
388 debug((char *) "%s| %s: INFO: No Username given\n", LogTime(), PROGRAM
);
389 SEND_BH("Invalid request. No Username");
392 rfc1738_unescape(user
);
393 nuser
= strchr(user
, '\\');
395 nuser8
= strstr(user
, "%5C");
396 if (!nuser
&& !nuser8
)
397 nuser8
= strstr(user
, "%5c");
398 domain
= strrchr(user
, '@');
399 if (nuser
|| nuser8
) {
408 up
= xstrdup(rfc1738_escape(nuser
));
409 np
= xstrdup(rfc1738_escape(netbios
));
411 debug((char *) "%s| %s: INFO: Got User: %s Netbios Name: %s\n", LogTime(), PROGRAM
, up
, np
);
413 log((char *) "%s| %s: INFO: Got User: %s Netbios Name: %s\n", LogTime(), PROGRAM
, up
, np
);
414 domain
= get_netbios_name(&margs
, netbios
);
423 up
= xstrdup(rfc1738_escape(user
));
425 dp
= xstrdup(rfc1738_escape(domain
));
426 if (!domain
&& margs
.ddomain
) {
427 domain
= xstrdup(margs
.ddomain
);
428 dp
= xstrdup(rfc1738_escape(domain
));
430 debug((char *) "%s| %s: INFO: Got User: %s set default domain: %s\n", LogTime(), PROGRAM
, up
, dp
);
432 log((char *) "%s| %s: INFO: Got User: %s set default domain: %s\n", LogTime(), PROGRAM
, up
, dp
);
435 debug((char *) "%s| %s: INFO: Got User: %s Domain: %s\n", LogTime(), PROGRAM
, up
, domain
? dp
: "NULL");
437 log((char *) "%s| %s: INFO: Got User: %s Domain: %s\n", LogTime(), PROGRAM
, up
, domain
? dp
: "NULL");
441 if (!strcmp(user
, "QQ") && domain
&& !strcmp(domain
, "QQ")) {
450 if ((group
= strtok(NULL
, " \n")) != NULL
) {
451 debug((char *) "%s| %s: INFO: Read group list %s from stdin\n", LogTime(), PROGRAM
, group
);
452 rfc1738_unescape(group
);
454 clean_gd(margs
.groups
);
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");
464 SEND_BH("No group list received on stdin");
465 debug((char *) "%s| %s: FATAL: No group list received on stdin\n", LogTime(), PROGRAM
);
469 if (check_memberof(&margs
, user
, domain
)) {
471 debug((char *) "%s| %s: DEBUG: OK\n", LogTime(), PROGRAM
);
474 debug((char *) "%s| %s: DEBUG: ERR\n", LogTime(), PROGRAM
);
484 *s
= (char)toupper((unsigned char) *s
);
492 main(int argc
, char *const argv
[])
494 setbuf(stdout
, NULL
);
498 if (fgets(buf
, sizeof(buf
) - 1, stdin
) == NULL
) {
500 fprintf(stdout
, "ERR\n");
501 fprintf(stderr
, "LDAP group authorisation not supported\n");