kerberos_ldap_group.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2017 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
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 
char * tlist
Definition: support.h:97
const char * LogTime(void)
char * strerror(int ern)
Definition: strerror.c:22
char * netbios
Definition: support.h:84
void init_args(struct main_args *margs)
int main(int argc, char *const argv[])
int mdepth
Definition: support.h:107
int debug_enabled
Definition: debug.cc:13
void error(char *format,...)
void log(char *format,...)
int i
Definition: membanger.c:49
#define xstrdup
struct ndstruct * next
Definition: support.h:86
#define safe_free(x)
Definition: xalloc.h:73
#define rfc1738_escape(x)
Definition: rfc1738.h:52
int create_gd(struct main_args *margs)
char * p
Definition: membanger.c:43
char * get_netbios_name(struct main_args *margs, char *netbios)
char * lserver
Definition: support.h:89
#define SEND_OK(x)
char * lbind
Definition: support.h:102
char * luser
Definition: support.h:100
void clean_args(struct main_args *margs)
char * glist
Definition: support.h:95
int create_ls(struct main_args *margs)
int create_nd(struct main_args *margs)
int getopt(int nargc, char *const *nargv, const char *ostr)
Definition: getopt.c:62
int check_memberof(struct main_args *margs, char *user, char *domain)
char * domain
Definition: support.h:90
char * ssl
Definition: support.h:104
static int debug
Definition: tcp-banger3.c:105
struct gdstruct * groups
Definition: support.h:110
struct gdstruct * next
Definition: support.h:81
void warn(char *format,...)
int rc_allow
Definition: support.h:105
int AD
Definition: support.h:106
struct lsstruct * next
Definition: support.h:91
char * ddomain
Definition: support.h:109
int nokerberos
Definition: support.h:108
#define SEND_BH(x)
char * domain
Definition: support.h:85
char * lpass
Definition: support.h:101
char * group
Definition: support.h:79
struct ndstruct * ndoms
Definition: support.h:111
char * domain
Definition: support.h:80
void rfc1738_unescape(char *url)
Definition: rfc1738.c:146
#define PROGRAM
Definition: support.h:188
SQUIDCEXTERN int log_enabled
Definition: support.h:115
char * lurl
Definition: support.h:103
struct lsstruct * lservs
Definition: support.h:112
char * nlist
Definition: support.h:98
#define SEND_ERR(x)
#define KERBEROS_LDAP_GROUP_VERSION
Definition: support.h:33
char * llist
Definition: support.h:99
char * optarg
Definition: getopt.c:51
#define NULL
Definition: types.h:166
char * ulist
Definition: support.h:96

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors