2 * Copyright (C) 1996-2018 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
;
88 void clean_gd(struct gdstruct
*gdsp
);
89 void clean_nd(struct ndstruct
*ndsp
);
90 void clean_ls(struct lsstruct
*lssp
);
93 clean_gd(struct gdstruct
*gdsp
)
95 struct gdstruct
*p
= NULL
, *pp
= NULL
;
104 safe_free(p
->domain
);
114 clean_nd(struct ndstruct
*ndsp
)
116 struct ndstruct
*p
= NULL
, *pp
= NULL
;
124 safe_free(p
->netbios
);
125 safe_free(p
->domain
);
135 clean_ls(struct lsstruct
*lssp
)
137 struct lsstruct
*p
= NULL
, *pp
= NULL
;
145 safe_free(p
->lserver
);
146 safe_free(p
->domain
);
156 clean_args(struct main_args
*margs
)
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
);
170 clean_gd(margs
->groups
);
171 margs
->groups
= NULL
;
174 clean_nd(margs
->ndoms
);
178 clean_ls(margs
->lservs
);
179 margs
->lservs
= NULL
;
186 main(int argc
, char *const argv
[])
189 char *user
, *domain
, *group
;
190 char *up
=NULL
, *dp
=NULL
, *np
=NULL
;
191 char *nuser
, *nuser8
= NULL
, *netbios
;
193 struct main_args margs
;
195 krb5_error_code code
= 0;
197 kparam
.context
= NULL
;
200 setbuf(stdout
, NULL
);
205 while (-1 != (opt
= getopt(argc
, argv
, "diasng:D:N:S:u:U:t:T:p:l:b:m:h"))) {
217 margs
.ssl
= xstrdup("yes");
220 margs
.nokerberos
= 1;
223 margs
.glist
= xstrdup(optarg
);
226 margs
.ddomain
= xstrdup(optarg
);
229 margs
.nlist
= xstrdup(optarg
);
232 margs
.luser
= xstrdup(optarg
);
235 margs
.ulist
= xstrdup(optarg
);
238 margs
.ulist
= xstrdup(optarg
);
241 margs
.tlist
= xstrdup(optarg
);
244 margs
.lpass
= xstrdup(optarg
);
246 memset(optarg
, 'X', strlen(optarg
));
249 margs
.lurl
= xstrdup(optarg
);
252 margs
.lbind
= xstrdup(optarg
);
255 margs
.mdepth
= atoi(optarg
);
258 margs
.llist
= xstrdup(optarg
);
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");
301 warn((char *) "%s| %s: WARNING: unknown option: -%c.\n", LogTime(), PROGRAM
, opt
);
305 debug((char *) "%s| %s: INFO: Starting version %s\n", LogTime(), PROGRAM
, KERBEROS_LDAP_GROUP_VERSION
);
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");
314 debug((char *) "%s| %s: INFO: no group list given expect it from stdin\n", LogTime(), PROGRAM
);
318 if (create_nd(&margs
)) {
319 debug((char *) "%s| %s: FATAL: Error in netbios list: %s\n", LogTime(), PROGRAM
, margs
.nlist
? margs
.nlist
: "NULL");
324 if (create_ls(&margs
)) {
325 debug((char *) "%s| %s: Error in ldap server list: %s\n", LogTime(), PROGRAM
, margs
.llist
? margs
.llist
: "NULL");
333 * Initialise Kerberos
336 code
= krb5_init_context(&kparam
.context
);
337 for (int i
=0; i
<MAX_DOMAINS
; i
++) {
338 kparam
.mem_ccache
[i
]=NULL
;
343 error((char *) "%s| %s: ERROR: Error while initialising Kerberos library : %s\n", LogTime(), PROGRAM
, error_message(code
));
352 if (fgets(buf
, sizeof(buf
) - 1, stdin
) == NULL
) {
354 debug((char *) "%s| %s: FATAL: fgets() failed! dying..... errno=%d (%s)\n", LogTime(), PROGRAM
, ferror(stdin
),
355 strerror(ferror(stdin
)));
357 SEND_BH(strerror(ferror(stdin
)));
362 exit(EXIT_FAILURE
); /* BIIG buffer */
364 SEND_BH("fgets NULL");
371 c
= (char *) memchr(buf
, '\n', sizeof(buf
) - 1);
375 SEND_BH("Invalid input. CR missing");
376 debug((char *) "%s| %s: ERR\n", LogTime(), PROGRAM
);
380 user
= strtok(buf
, " \n");
382 debug((char *) "%s| %s: INFO: No Username given\n", LogTime(), PROGRAM
);
383 SEND_BH("Invalid request. No Username");
386 rfc1738_unescape(user
);
387 nuser
= strchr(user
, '\\');
389 nuser8
= strstr(user
, "%5C");
390 if (!nuser
&& !nuser8
)
391 nuser8
= strstr(user
, "%5c");
392 domain
= strrchr(user
, '@');
393 if (nuser
|| nuser8
) {
402 up
= xstrdup(rfc1738_escape(nuser
));
403 np
= xstrdup(rfc1738_escape(netbios
));
405 debug((char *) "%s| %s: INFO: Got User: %s Netbios Name: %s\n", LogTime(), PROGRAM
, up
, np
);
407 log((char *) "%s| %s: INFO: Got User: %s Netbios Name: %s\n", LogTime(), PROGRAM
, up
, np
);
408 domain
= get_netbios_name(&margs
, netbios
);
417 up
= xstrdup(rfc1738_escape(user
));
419 dp
= xstrdup(rfc1738_escape(domain
));
420 if (!domain
&& margs
.ddomain
) {
421 domain
= xstrdup(margs
.ddomain
);
422 dp
= xstrdup(rfc1738_escape(domain
));
424 debug((char *) "%s| %s: INFO: Got User: %s set default domain: %s\n", LogTime(), PROGRAM
, up
, dp
);
426 log((char *) "%s| %s: INFO: Got User: %s set default domain: %s\n", LogTime(), PROGRAM
, up
, dp
);
429 debug((char *) "%s| %s: INFO: Got User: %s Domain: %s\n", LogTime(), PROGRAM
, up
, domain
? dp
: "NULL");
431 log((char *) "%s| %s: INFO: Got User: %s Domain: %s\n", LogTime(), PROGRAM
, up
, domain
? dp
: "NULL");
435 if (!strcmp(user
, "QQ") && domain
&& !strcmp(domain
, "QQ")) {
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
);
448 clean_gd(margs
.groups
);
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");
458 SEND_BH("No group list received on stdin");
459 debug((char *) "%s| %s: FATAL: No group list received on stdin\n", LogTime(), PROGRAM
);
463 if (check_memberof(&margs
, user
, domain
)) {
465 debug((char *) "%s| %s: DEBUG: OK\n", LogTime(), PROGRAM
);
468 debug((char *) "%s| %s: DEBUG: ERR\n", LogTime(), PROGRAM
);
478 *s
= (char)toupper((unsigned char) *s
);
486 main(int argc
, char *const argv
[])
488 setbuf(stdout
, NULL
);
492 if (fgets(buf
, sizeof(buf
) - 1, stdin
) == NULL
) {
494 fprintf(stdout
, "ERR\n");
495 fprintf(stderr
, "LDAP group authorisation not supported\n");