1 /* ext_edirectory_userip_acl - Copyright (C) 2009-2011 Chad E. Naugle
3 ********************************************************************************
5 * This file is part of ext_edirectory_userip_acl.
7 * ext_edirectory_userip_acl is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 2 of the License, or
10 * (at your option) any later version.
12 * ext_edirectory_userip_acl is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with squid_edir_iplookup. If not, see <http://www.gnu.org/licenses/>.
20 ********************************************************************************
22 * ext_edirectory_userip_acl.cc -- Rev 2011-03-28
24 * - Misc code cleanups using "static", and 64-bit SLES fix for SearchFilterLDAP()
28 /* Squid-3.X includes */
30 #include "helpers/defines.h"
34 #define EDUI_PROGRAM_NAME "ext_edirectory_userip_acl"
35 #define EDUI_PROGRAM_VERSION "2.1"
62 #ifdef HAVE_ARPA_INET_H
63 #include <arpa/inet.h>
65 #define LDAP_DEPRECATED 1 /* Set flag for enabling classic ldap functions */
79 #ifdef HELPER_INPUT_BUFFER
80 #define EDUI_MAXLEN HELPER_INPUT_BUFFER
82 #define EDUI_MAXLEN 4096 /* Modified to improve performance, unless HELPER_INPUT_BUFFER exists */
85 /* ldap compile options */
91 /* define LDAP_AUTH_TLS
92 * - ldap.h Hack for cleaner code, if it does not provide it.
95 # ifndef LDAP_AUTH_TLS
96 # define LDAP_AUTH_TLS ((ber_tag_t) 0xb3U)
100 /* conf_t - status flags */
101 #define EDUI_MODE_INIT 0x01
102 #define EDUI_MODE_DEBUG 0x02 /* Replace with Squid's debug system */
103 #define EDUI_MODE_TLS 0x04
104 #define EDUI_MODE_IPV4 0x08
105 #define EDUI_MODE_IPV6 0x10
106 #define EDUI_MODE_GROUP 0x20 /* Group is REQUIRED */
107 #define EDUI_MODE_PERSIST 0x40 /* Persistent LDAP connections */
108 #define EDUI_MODE_KILL 0x80
110 /* conf_t - Program configuration struct typedef */
112 char program
[EDUI_MAXLEN
];
113 char basedn
[EDUI_MAXLEN
];
114 char host
[EDUI_MAXLEN
];
115 char attrib
[EDUI_MAXLEN
];
116 char dn
[EDUI_MAXLEN
];
117 char passwd
[EDUI_MAXLEN
];
118 char search_filter
[EDUI_MAXLEN
]; /* Base search_filter that gets copied to edui_ldap_t */
122 time_t persist_timeout
;
126 /* edui_ldap_t - status flags */
127 #define LDAP_INIT_S 0x0001
128 #define LDAP_OPEN_S 0x0002
129 #define LDAP_BIND_S 0x0004
130 #define LDAP_SEARCH_S 0x0008 /* We got data */
131 #define LDAP_VAL_S 0x0010 /* Data has been copied to l->val */
132 #define LDAP_CLOSE_S 0x0020
133 #define LDAP_PERSIST_S 0x0040 /* Persistent connection */
134 #define LDAP_IDLE_S 0x0080 /* Connection is idle */
135 #define LDAP_SSL_S 0x0100
136 #define LDAP_TLS_S 0x0200
137 #define LDAP_IPV4_S 0x0400 /* Search IP is IPv4 */
138 #define LDAP_IPV6_S 0x0800 /* Search IP is IPv6 */
140 /* edui_ldap_t - Meaningful error codes */
141 #define LDAP_ERR_NULL -1 /* Null edui_ldap_t pointer */
142 #define LDAP_ERR_POINTER -2 /* Null l->lp pointer */
143 #define LDAP_ERR_PARAM -3 /* Null or Missing parameters */
144 #define LDAP_ERR_INIT -4 /* Not initalized */
145 #define LDAP_ERR_OPEN -5 /* Not open */
146 #define LDAP_ERR_CONNECT -6 /* Unable to connect */
147 #define LDAP_ERR_BIND -7 /* Not bound */
148 #define LDAP_ERR_SEARCHED -8 /* Already Searched */
149 #define LDAP_ERR_NOT_SEARCHED -9 /* Not searching */
150 #define LDAP_ERR_INVALID -10 /* Invalid parameter */
151 #define LDAP_ERR_OOB -11 /* Out of bounds value */
152 #define LDAP_ERR_PERSIST -12 /* Persistent mode is not active */
153 #define LDAP_ERR_DATA -13 /* Required data missing */
154 #define LDAP_ERR_NOTFOUND -14 /* Item not found */
155 #define LDAP_ERR_OTHER -15 /* Other Generic Error condition */
156 #define LDAP_ERR_FAILED -16 /* Operation failed */
157 #define LDAP_ERR_SUCCESS -17 /* Operation successful */
159 /* edui_ldap_t - struct typedef */
164 char basedn
[EDUI_MAXLEN
];
165 char host
[EDUI_MAXLEN
];
166 char dn
[EDUI_MAXLEN
];
167 char passwd
[EDUI_MAXLEN
];
168 char search_filter
[EDUI_MAXLEN
]; /* search_group gets appended here by GroupLDAP */
169 char search_ip
[EDUI_MAXLEN
]; /* Could be IPv4 or IPv6, set by ConvertIP */
170 char userid
[EDUI_MAXLEN
]; /* Resulting userid */
173 unsigned long type
; /* Type of bind */
176 int err
; /* LDAP error code */
178 int num_ent
; /* Number of entry's found via search */
179 int num_val
; /* Number of value's found via getval */
182 /* Global function prototypes */
183 static void local_printfx(const char *,...);
184 static int StringSplit(char *, char, char *, size_t);
185 static int BinarySplit(void *, size_t, char, void *, size_t);
186 static void DisplayVersion();
187 static void DisplayUsage();
188 static void InitConf();
189 static void DisplayConf();
190 static void InitLDAP(edui_ldap_t
*);
191 static int OpenLDAP(edui_ldap_t
*, char *, unsigned int);
192 static int CloseLDAP(edui_ldap_t
*);
193 static int SetVerLDAP(edui_ldap_t
*, int);
194 static int BindLDAP(edui_ldap_t
*, char *, char *, unsigned int);
195 static int ConvertIP(edui_ldap_t
*, char *);
196 static int ResetLDAP(edui_ldap_t
*);
197 static int SearchFilterLDAP(edui_ldap_t
*, char *);
198 static int SearchLDAP(edui_ldap_t
*, int, char *, char **);
199 static int SearchIPLDAP(edui_ldap_t
*);
200 const char *ErrLDAP(int);
201 extern "C" void SigTrap(int);
203 /* Global variables */
204 const char *search_attrib
[] = { "cn", "uid", "networkAddress", "groupMembership", NULL
};
205 static edui_conf_t edui_conf
;
206 static edui_ldap_t edui_ldap
;
212 * Print formatted message to stderr AND stdout, without preformatting.
214 * - Exists as a hack, because SEND_OK() does not appear to work here.
218 local_printfx(const char *msg
,...)
220 char prog
[EDUI_MAXLEN
], dbuf
[EDUI_MAXLEN
];
224 if (edui_conf
.program
[0] == '\0')
225 xstrncpy(prog
, EDUI_PROGRAM_NAME
, sizeof(prog
));
227 xstrncpy(prog
, edui_conf
.program
, sizeof(prog
));
231 debug("local_printfx() FAILURE, no data.\n");
236 x
= vsnprintf(dbuf
, sz
, msg
, ap
);
245 debug("local_printfx() FAILURE: %zd\n", x
);
248 /* stdout needs to be flushed for it to work with Squid */
253 * StringSplit() - <string-to-split> <char> <split-object> <obj-size>
255 * Breaks down string, splitting out element <char> into <split-object>, and removing it from string.
256 * Will not exceed size tolerances.
260 StringSplit(char *In_Str
, char chr
, char *Out_Str
, size_t Out_Sz
)
262 if ((In_Str
== NULL
) || (Out_Str
== NULL
))
265 size_t In_Len
= strlen(In_Str
) + 1;
267 // find the char delimiter position...
269 while (*p
!= chr
&& *p
!= '\0' && (In_Str
+In_Len
) > p
) {
273 size_t i
= (p
-In_Str
);
275 // token to big for the output buffer
279 // wipe the unused Out_Obj area
280 memset(Out_Str
+i
, 0, Out_Sz
-i
);
281 // copy token from In_Str to Out_Str
282 memcpy(Out_Str
, In_Str
, i
);
284 // omit the delimiter
289 // chr not found (or \0 found first). Wipe whole input buffer.
290 memset(In_Str
, 0, In_Len
);
292 // Returning <0 breaks current ConvertIP() code for last object
296 // move the unused In_Str forward
297 memmove(In_Str
, p
, In_Len
-i
);
298 // wipe the end of In_Str
299 memset(In_Str
+In_Len
-i
, 0, i
);
304 * BinarySplit() - <binary-to-split> <bin-size> <char> <split-object> <obj-size>
306 * Breaks down Binary Block, splitting out element <char> into <split-object>, and removing it from Block, padding remainder with '\0'.
307 * Will not exceed size tolerances.
311 BinarySplit(void *In_Obj
, size_t In_Sz
, char chr
, void *Out_Obj
, size_t Out_Sz
)
314 if ((In_Obj
== NULL
) || (Out_Obj
== NULL
))
317 char *in
= static_cast<char*>(In_Obj
);
318 char *out
= static_cast<char*>(Out_Obj
);
320 // find the char delimiter position...
321 char *p
= static_cast<char*>(In_Obj
);
322 while (*p
!= chr
&& (in
+In_Sz
) > p
) {
328 // token to big for the output buffer
332 // wipe the unused Out_Obj area
333 memset(out
+i
, 0, Out_Sz
-i
);
334 // copy token from In_Obj to Out_Obj
335 memcpy(Out_Obj
, In_Obj
, i
);
337 // omit the delimiter
343 memset(In_Obj
, 0, In_Sz
);
345 // Returning <0 breaks current code for last object
349 // move the unused In_Obj forward
350 memmove(In_Obj
, p
, In_Sz
-i
);
351 // wipe the end of In_Obj
352 memset(in
+In_Sz
-i
, 0, i
);
356 /* Displays version information */
360 local_printfx("Squid eDirectory IP Lookup Helper %s. Copyright (C) 2009-2011 Chad E. Naugle\n", EDUI_PROGRAM_VERSION
);
363 /* Displays program usage information */
369 local_printfx("Usage: %s\n", edui_conf
.program
);
370 local_printfx(" -H <host> -p <port> [-Z] [-P] [-v 3] -b <basedn> -s <scope>\n");
371 local_printfx(" -D <binddn> -W <bindpass> -F <search-filter> [-G] \n\n");
372 local_printfx(" -d : Debug Mode.\n");
373 local_printfx(" -4 : Force Addresses to be in IPv4 (127.0.0.1 format).\n");
374 local_printfx(" -6 : Force Addresses to be in IPv6 (::1 format).\n");
375 local_printfx(" -H <host> : Specify hostname/ip of server.\n");
376 local_printfx(" -p <port> : Specify port number. (Range 1-65535)\n");
377 local_printfx(" -Z : Enable TLS security.\n");
378 local_printfx(" -P : Use persistent connections.\n");
379 local_printfx(" -t <sec> : Timeout factor for persistent connections. (Default is 60 sec, set to 0 for never timeout)\n");
380 local_printfx(" -v <1,2,3> : Set LDAP version to 1, 2, or 3.\n");
381 local_printfx(" -b <base> : Specify Base DN. (ie. \"o=ORG\")\n");
382 local_printfx(" -s <scope> : Specify LDAP Search Scope (base, one, sub; defaults to 'one').\n");
383 local_printfx(" -D <dn> : Specify Binding DN. (ie. cn=squid,o=ORG)\n");
384 local_printfx(" -W <pass> : Specify Binding password.\n");
385 local_printfx(" -u <attrib> : Set userid attribute (Defaults to \"cn\").\n");
386 local_printfx(" -F <filter> : Specify LDAP search filter. (ie. \"(objectClass=User)\")\n");
387 local_printfx(" -G : Specify if LDAP search group is required. (ie. \"groupMembership=\")\n");
388 local_printfx(" -V : Display version & exit.\n");
389 local_printfx(" -h : This screen & exit.\n");
393 /* Initalizes program's configuration paremeters */
397 *(edui_conf
.program
) = '\0';
398 *(edui_conf
.basedn
) = '\0';
399 *(edui_conf
.host
) = '\0';
400 *(edui_conf
.attrib
) = '\0';
401 *(edui_conf
.dn
) = '\0';
402 *(edui_conf
.passwd
) = '\0';
403 *(edui_conf
.search_filter
) = '\0';
404 edui_conf
.scope
= -1;
407 edui_conf
.persist_timeout
= -1;
409 edui_conf
.mode
|= EDUI_MODE_INIT
;
411 /* Set defaults from compile-time-options, if provided, but depriciated. */
413 xstrncpy(edui_conf
.basedn
, EDUI_BASE_DN
, sizeof(edui_conf
.basedn
));
415 #ifdef EDUI_DEFAULT_HOST
416 xstrncpy(edui_conf
.host
, EDUI_DEFAULT_HOST
, sizeof(edui_conf
.host
));
419 xstrncpy(edui_conf
.dn
, EDUI_BIND_DN
, sizeof(edui_conf
.dn
));
421 #ifdef EDUI_BIND_PASS
422 xstrncpy(edui_conf
.passwd
, EDUI_BIND_PASS
, sizeof(edui_conf
.passwd
));
424 #ifdef EDUI_USER_ATTRIB
425 xstrncpy(edui_conf
.attrib
, EDUI_USER_ATTRIB
, sizeof(edui_conf
.attrib
));
427 #ifdef EDUI_SEARCH_FILTER
428 xstrncpy(edui_conf
.search_filter
, EDUI_SEARCH_FILTER
, sizeof(edui_conf
.search_filter
));
430 #ifdef EDUI_SEARCH_SCOPE
431 if (!strcmp(EDUI_SEARCH_SCOPE
, "base"))
433 else if (!strcmp(EDUI_SEARCH_SCOPE
, "one"))
435 else if (!strcmp(EDUI_SEARCH_SCOPE
, "sub"))
440 #ifdef EDUI_LDAP_VERSION
441 edui_conf
.ver
= EDUI_LDAP_VERSION
;
443 #ifdef EDUI_DEFAULT_PORT
444 edui_conf
.port
= EDUI_DEFAULT_PORT
;
446 #ifdef EDUI_FORCE_IPV4
447 edui_conf
.mode
|= EDUI_MODE_IPV4
;
449 #ifdef EDUI_FORCE_IPV6
450 edui_conf
.mode
|= EDUI_MODE_IPV6
;
453 edui_conf
.mode
|= EDUI_MODE_TLS
;
455 #ifdef EDUI_USE_PERSIST
456 edui_conf
.mode
|= EDUI_MODE_PERSIST
;
458 #ifdef EDUI_PERSIST_TIMEOUT
459 edui_conf
.persist_timeout
= EDUI_PERSIST_TIMEOUT
;
461 #ifdef EDUI_GROUP_REQUIRED
462 edui_conf
.mode
|= EDUI_MODE_GROUP
;
465 edui_conf
.mode
|= EDUI_MODE_DEBUG
;
469 /* Displays running configuration */
473 if (!(edui_conf
.mode
& EDUI_MODE_DEBUG
))
477 local_printfx("Configuration:\n");
478 local_printfx(" EDUI_MAXLEN: %zd\n", EDUI_MAXLEN
);
479 if (edui_conf
.mode
& EDUI_MODE_DEBUG
)
480 local_printfx(" Debug mode: ON\n");
482 local_printfx(" Debug mode: OFF\n");
483 if (edui_conf
.mode
& EDUI_MODE_IPV4
)
484 local_printfx(" Address format: IPv4 (127.0.0.1)\n");
485 else if (edui_conf
.mode
& EDUI_MODE_IPV6
)
486 local_printfx(" Address format: IPv6 (::1)\n");
488 local_printfx(" Address format: Not enforced.\n");
489 if (edui_conf
.host
[0] != '\0')
490 local_printfx(" Hostname: %s\n", edui_conf
.host
);
492 local_printfx(" Hostname: localhost\n");
493 if (edui_conf
.port
> 0)
494 local_printfx(" Port: %d\n", edui_conf
.port
);
496 local_printfx(" Port: %d\n", LDAP_PORT
);
497 if (edui_conf
.mode
& EDUI_MODE_TLS
)
498 local_printfx(" TLS mode: ON\n");
500 local_printfx(" TLS mode: OFF\n");
501 if (edui_conf
.mode
& EDUI_MODE_PERSIST
) {
502 local_printfx(" Persistent mode: ON\n");
503 if (edui_conf
.persist_timeout
> 0)
504 local_printfx(" Persistent mode idle timeout: %d\n", edui_conf
.persist_timeout
);
506 local_printfx(" Persistent mode idle timeout: OFF\n");
508 local_printfx(" Persistent mode: OFF\n");
509 local_printfx(" LDAP Version: %d\n", edui_conf
.ver
);
510 if (edui_conf
.basedn
[0] != '\0')
511 local_printfx(" Base DN: %s\n", edui_conf
.basedn
);
513 local_printfx(" Base DN: None\n");
514 if (edui_conf
.dn
[0] != '\0')
515 local_printfx(" Binding DN: %s\n", edui_conf
.dn
);
517 local_printfx(" Binding DN: Anonymous\n");
518 if (edui_conf
.passwd
[0] != '\0')
519 local_printfx(" Binding Password: %s\n", edui_conf
.passwd
);
521 local_printfx(" Binding Password: None\n");
522 switch (edui_conf
.scope
) {
524 local_printfx(" Search Scope: base\n");
527 local_printfx(" Search Scope: one level\n");
530 local_printfx(" Search Scope: subtree\n");
533 local_printfx(" Search Scope: base\n");
536 if (edui_conf
.attrib
[0] != '\0')
537 local_printfx(" Search Attribute: %s\n", edui_conf
.attrib
);
539 local_printfx(" Search Attribute: cn\n");
540 if (edui_conf
.search_filter
[0] != '\0')
541 local_printfx(" Search Filter: %s\n", edui_conf
.search_filter
);
543 local_printfx(" Search Filter: (&(objectClass=User)(networkAddress=*))\n");
544 if (edui_conf
.mode
& EDUI_MODE_GROUP
)
545 local_printfx(" Search Group Required: Yes\n");
547 local_printfx(" Search Group Required: No\n");
551 /* InitLDAP() - <edui_ldap_t>
553 * Initalize LDAP structure for use, zeroing out all variables.
557 InitLDAP(edui_ldap_t
*l
)
559 if (l
== NULL
) return;
565 ldap_value_free_len(l
->val
);
572 *(l
->search_filter
) = '\0';
574 memset(l
->search_ip
, '\0', sizeof(l
->search_ip
));
576 l
->status
|= LDAP_INIT_S
;
580 l
->err
= -1; /* Set error to LDAP_SUCCESS by default */
583 l
->num_ent
= 0; /* Number of entries in l->lm */
584 l
->num_val
= 0; /* Number of entries in l->val */
586 /* Set default settings from conf */
587 if (edui_conf
.basedn
[0] != '\0')
588 xstrncpy(l
->basedn
, edui_conf
.basedn
, sizeof(l
->basedn
));
589 if (edui_conf
.host
[0] != '\0')
590 xstrncpy(l
->host
, edui_conf
.host
, sizeof(l
->host
));
591 if (edui_conf
.port
!= 0)
592 l
->port
= edui_conf
.port
;
593 if (edui_conf
.dn
[0] != '\0')
594 xstrncpy(l
->dn
, edui_conf
.dn
, sizeof(l
->dn
));
595 if (edui_conf
.passwd
[0] != '\0')
596 xstrncpy(l
->passwd
, edui_conf
.passwd
, sizeof(l
->passwd
));
597 if (edui_conf
.search_filter
[0] != '\0')
598 xstrncpy(l
->search_filter
, edui_conf
.search_filter
, sizeof(l
->search_filter
));
599 if (!(edui_conf
.scope
< 0))
600 l
->scope
= edui_conf
.scope
;
603 /* OpenLDAP() - <edui_ldap_t> <host> <port>
605 * Build LDAP struct with hostname and port, and ready it for binding.
609 OpenLDAP(edui_ldap_t
*l
, char *h
, unsigned int p
)
611 if ((l
== NULL
) || (h
== NULL
)) return LDAP_ERR_NULL
;
612 if (!(l
->status
& LDAP_INIT_S
)) return LDAP_ERR_INIT
; /* Not initalized, or might be in use */
613 if (l
->status
& LDAP_OPEN_S
) return LDAP_ERR_OPEN
; /* Already open */
614 if (l
->status
& LDAP_BIND_S
) return LDAP_ERR_BIND
; /* Already bound */
616 xstrncpy(l
->host
, h
, sizeof(l
->host
));
620 l
->port
= LDAP_PORT
; /* Default is port 389 */
623 if (l
->port
== LDAPS_PORT
)
624 l
->status
|= (LDAP_SSL_S
| LDAP_TLS_S
); /* SSL Port: 636 */
628 l
->lp
= ldap_init(l
->host
, l
->port
);
630 l
->lp
= ldap_open(l
->host
, l
->port
);
633 l
->err
= LDAP_CONNECT_ERROR
;
634 return LDAP_ERR_CONNECT
; /* Unable to connect */
637 // l->status &= ~(LDAP_INIT_S);
638 l
->status
|= LDAP_OPEN_S
;
639 l
->err
= LDAP_SUCCESS
;
640 return LDAP_ERR_SUCCESS
;
644 /* CloseLDAP() - <edui_ldap_t>
646 * Close LDAP connection, and clean up data structure.
650 CloseLDAP(edui_ldap_t
*l
)
653 if (l
== NULL
) return LDAP_ERR_NULL
;
654 if (l
->lp
== NULL
) return LDAP_ERR_NULL
;
655 if (!(l
->status
& LDAP_INIT_S
)) return LDAP_ERR_INIT
; /* Connection not initalized */
656 if (!(l
->status
& LDAP_OPEN_S
)) return LDAP_ERR_OPEN
; /* Connection not open */
662 if (l
->val
!= NULL
) {
663 ldap_value_free_len(l
->val
);
667 /* okay, so it's open, close it - No need to check other criteria */
668 s
= ldap_unbind(l
->lp
);
669 if (s
== LDAP_SUCCESS
) {
670 l
->status
= LDAP_INIT_S
;
672 l
->err
= s
; /* Set LDAP error code */
673 return LDAP_ERR_SUCCESS
;
675 l
->err
= s
; /* Set LDAP error code */
676 return LDAP_ERR_FAILED
;
680 /* SetVerLDAP() - <edui_ldap_t> <version>
682 * Set LDAP version number for connection to <version> of 1, 2, or 3
686 SetVerLDAP(edui_ldap_t
*l
, int v
)
689 if (l
== NULL
) return LDAP_ERR_NULL
;
690 if ((v
> 3) || (v
< 1)) return LDAP_ERR_PARAM
;
691 if (l
->lp
== NULL
) return LDAP_ERR_POINTER
;
692 if (!(l
->status
& LDAP_INIT_S
)) return LDAP_ERR_INIT
; /* Not initalized */
693 if (!(l
->status
& LDAP_OPEN_S
)) return LDAP_ERR_OPEN
; /* Not open */
694 if (l
->status
& LDAP_BIND_S
) return LDAP_ERR_BIND
; /* Already bound */
697 x
= ldap_set_option(l
->lp
, LDAP_OPT_PROTOCOL_VERSION
, &v
);
698 if (x
== LDAP_SUCCESS
) {
700 l
->err
= x
; /* Set LDAP error code */
701 return LDAP_ERR_SUCCESS
;
703 l
->err
= x
; /* Set LDAP error code */
704 return LDAP_ERR_FAILED
;
708 /* BindLDAP() - <edui_ldap_t> <use-dn> <use-password> <type>
710 * Bind LDAP connection (Open) using optional dn and password, of <type>
714 BindLDAP(edui_ldap_t
*l
, char *dn
, char *pw
, unsigned int t
)
717 if (l
== NULL
) return LDAP_ERR_NULL
;
718 if (!(l
->status
& LDAP_INIT_S
)) return LDAP_ERR_INIT
; /* Not initalized */
719 if (!(l
->status
& LDAP_OPEN_S
)) return LDAP_ERR_OPEN
; /* Not open */
720 if (l
->status
& LDAP_BIND_S
) return LDAP_ERR_BIND
; /* Already bound */
721 if (l
->lp
== NULL
) return LDAP_ERR_POINTER
; /* Error */
723 /* Copy details - dn and pw CAN be NULL for anonymous and/or TLS */
725 if ((l
->basedn
[0] != '\0') && (strstr(dn
, l
->basedn
) == NULL
)) {
726 /* We got a basedn, but it's not part of dn */
727 xstrncpy(l
->dn
, dn
, sizeof(l
->dn
));
728 strncat(l
->dn
, ",", 1);
729 strncat(l
->dn
, l
->basedn
, strlen(l
->basedn
));
731 xstrncpy(l
->dn
, dn
, sizeof(l
->dn
));
734 xstrncpy(l
->passwd
, pw
, sizeof(l
->passwd
));
741 case LDAP_AUTH_SIMPLE
:
747 #ifdef LDAP_AUTH_KRBV4
748 case LDAP_AUTH_KRBV4
:
752 #ifdef LDAP_AUTH_KRBV41
753 case LDAP_AUTH_KRBV41
:
757 #ifdef LDAP_AUTH_KRBV42
758 case LDAP_AUTH_KRBV42
:
763 case LDAP_AUTH_TLS
: /* Added for chicken switch to TLS-enabled without using SSL */
768 l
->type
= LDAP_AUTH_NONE
;
769 break; /* Default to anonymous bind */
773 #if defined(LDAP_AUTH_TLS) && defined(NETSCAPE_SSL) && HAVE_LDAP_START_TLS_S
774 if (l
->type
== LDAP_AUTH_TLS
)
775 s
= ldap_start_tls_s(l
->lp
, NULL
, NULL
);
778 s
= ldap_bind_s(l
->lp
, l
->dn
, l
->passwd
, l
->type
);
779 if (s
== LDAP_SUCCESS
) {
780 l
->status
|= LDAP_BIND_S
; /* Success */
781 l
->err
= s
; /* Set LDAP error code */
782 return LDAP_ERR_SUCCESS
;
784 l
->err
= s
; /* Set LDAP error code */
785 return LDAP_ERR_FAILED
;
790 * ConvertIP() - <edui_ldap_t> <ip>
792 * Take an IPv4 address in dot-decimal or IPv6 notation, and convert to 2-digit HEX stored in l->search_ip
793 * This is the networkAddress that we search LDAP for.
795 * PENDING -- CHANGE OVER TO inet*_pton, but inet6_pton does not provide the correct syntax
799 ConvertIP(edui_ldap_t
*l
, char *ip
)
801 char bufa
[EDUI_MAXLEN
], bufb
[EDUI_MAXLEN
], obj
[EDUI_MAXLEN
];
806 int i
, j
, t
, swi
; /* IPv6 "::" cut over toggle */
807 if (l
== NULL
) return LDAP_ERR_NULL
;
808 if (ip
== NULL
) return LDAP_ERR_PARAM
;
809 if (!(l
->status
& LDAP_INIT_S
)) return LDAP_ERR_INIT
; /* Not initalized */
810 if (!(l
->status
& LDAP_OPEN_S
)) return LDAP_ERR_OPEN
; /* Not open */
811 if (!(l
->status
& LDAP_BIND_S
)) return LDAP_ERR_BIND
; /* Not bound */
813 y
= memchr((void *)ip
, ':', EDUI_MAXLEN
);
814 z
= memchr((void *)ip
, '.', EDUI_MAXLEN
);
815 if ((y
!= NULL
) && (z
!= NULL
)) {
818 return LDAP_ERR_INVALID
;
820 if ((y
!= NULL
) && (edui_conf
.mode
& EDUI_MODE_IPV4
)) {
821 /* IPv4 Mode forced */
822 return LDAP_ERR_INVALID
;
823 } else if (y
!= NULL
) {
825 if (l
->status
& LDAP_IPV4_S
)
826 l
->status
&= ~(LDAP_IPV4_S
);
827 if (!(l
->status
& LDAP_IPV6_S
))
828 l
->status
|= (LDAP_IPV6_S
);
831 if ((z
!= NULL
) && (edui_conf
.mode
& EDUI_MODE_IPV6
)) {
832 /* IPv6 Mode forced */
833 return LDAP_ERR_INVALID
;
834 } else if (z
!= NULL
) {
836 if (l
->status
& LDAP_IPV6_S
)
837 l
->status
&= ~(LDAP_IPV6_S
);
838 if (!(l
->status
& LDAP_IPV4_S
))
839 l
->status
|= (LDAP_IPV4_S
);
846 /* StringSplit() will zero out bufa & obj at each call */
847 memset(l
->search_ip
, '\0', sizeof(l
->search_ip
));
848 xstrncpy(bufa
, ip
, sizeof(bufa
)); /* To avoid segfaults, use bufa instead of ip */
850 if (l
->status
& LDAP_IPV6_S
) {
851 /* Search for :: in string */
852 if ((bufa
[0] == ':') && (bufa
[1] == ':')) {
853 /* bufa starts with a ::, so just copy and clear */
854 xstrncpy(bufb
, bufa
, sizeof(bufb
));
856 swi
++; /* Indicates that there is a bufb */
857 } else if ((bufa
[0] == ':') && (bufa
[1] != ':')) {
858 /* bufa starts with a :, a typo so just fill in a ':', cat and clear */
860 strncat(bufb
, bufa
, strlen(bufa
));
862 swi
++; /* Indicates that there is a bufb */
864 p
= strstr(bufa
, "::");
866 /* Found it, break bufa down and split into bufb here */
872 swi
++; /* Indicates that there is a bufb */
880 if ((l
->status
& LDAP_IPV4_S
) && (swi
== 0)) {
881 /* Break down IPv4 address */
882 t
= StringSplit(bufa
, '.', obj
, sizeof(obj
));
885 x
= strtol(obj
, (char **)NULL
, 10);
886 if (((x
< 0) || (x
> 255)) || ((errno
!= 0) && (x
== 0)) || ((obj
[0] != '0') && (x
== 0)))
887 return LDAP_ERR_OOB
; /* Out of bounds -- Invalid address */
888 memset(hexc
, '\0', sizeof(hexc
));
889 int hlen
= snprintf(hexc
, sizeof(hexc
), "%02X", (int)x
);
890 strncat(l
->search_ip
, hexc
, hlen
);
892 break; /* reached end of octet */
893 } else if (l
->status
& LDAP_IPV6_S
) {
894 /* Break down IPv6 address */
896 t
= StringSplit(bufb
, ':', obj
, sizeof(obj
)); /* After "::" */
898 t
= StringSplit(bufa
, ':', obj
, sizeof(obj
)); /* Before "::" */
899 /* Convert octet by size (t) - and fill 0's */
900 switch (t
) { /* IPv6 is already in HEX, copy contents */
902 hexc
[0] = (char) toupper((int)obj
[0]);
905 return LDAP_ERR_OOB
; /* Out of bounds */
906 hexc
[1] = (char) toupper((int)obj
[1]);
909 return LDAP_ERR_OOB
; /* Out of bounds */
911 strncat(l
->search_ip
, hexc
, 2);
912 hexc
[0] = (char) toupper((int)obj
[2]);
915 return LDAP_ERR_OOB
; /* Out of bounds */
916 hexc
[1] = (char) toupper((int)obj
[3]);
919 return LDAP_ERR_OOB
; /* Out of bounds */
921 strncat(l
->search_ip
, hexc
, 2);
925 hexc
[1] = (char) toupper((int)obj
[0]);
928 return LDAP_ERR_OOB
; /* Out of bounds */
930 strncat(l
->search_ip
, hexc
, 2);
931 hexc
[0] = (char) toupper((int)obj
[1]);
934 return LDAP_ERR_OOB
; /* Out of bounds */
935 hexc
[1] = (char) toupper((int)obj
[2]);
938 return LDAP_ERR_OOB
; /* Out of bounds */
940 strncat(l
->search_ip
, hexc
, 2);
943 strncat(l
->search_ip
, "00", 2);
944 hexc
[0] = (char) toupper((int)obj
[0]);
947 return LDAP_ERR_OOB
; /* Out of bounds */
948 hexc
[1] = (char) toupper((int)obj
[1]);
951 return LDAP_ERR_OOB
; /* Out of bounds */
953 strncat(l
->search_ip
, hexc
, 2);
956 strncat(l
->search_ip
, "00", 2);
958 hexc
[1] = (char) toupper((int)obj
[0]);
961 return LDAP_ERR_OOB
; /* Out of bounds */
963 strncat(l
->search_ip
, hexc
, 2);
970 /* Code to pad the address with 0's between a '::' */
971 if ((strlen(bufa
) == 0) && (swi
== 1)) {
972 /* We are *AT* the split, pad in some 0000 */
974 /* How many ':' exist in bufb ? */
976 for (i
= 0; i
< t
; i
++) {
980 j
--; /* Preceeding "::" doesn't count */
981 t
= 8 - (strlen(l
->search_ip
) / 4) - j
; /* Remainder */
983 for (i
= 0; i
< t
; i
++)
984 strncat(l
->search_ip
, "0000", 4);
988 if ((bufa
[0] == '\0') && (swi
> 0)) {
994 s
= strlen(l
->search_ip
);
996 /* CHECK sizes of address, truncate or pad */
997 /* if "::" is at end of ip, then pad another block or two */
998 while ((l
->status
& LDAP_IPV6_S
) && (s
< 32)) {
999 strncat(l
->search_ip
, "0000", 4);
1000 s
= strlen(l
->search_ip
);
1002 if ((l
->status
& LDAP_IPV6_S
) && (s
> 32)) {
1003 /* Too long, truncate */
1004 l
->search_ip
[32] = '\0';
1005 s
= strlen(l
->search_ip
);
1007 /* If at end of ip, and its not long enough, then pad another block or two */
1008 while ((l
->status
& LDAP_IPV4_S
) && (s
< 8)) {
1009 strncat(l
->search_ip
, "00", 2);
1010 s
= strlen(l
->search_ip
);
1012 if ((l
->status
& LDAP_IPV4_S
) && (s
> 8)) {
1013 /* Too long, truncate */
1014 l
->search_ip
[8] = '\0';
1015 s
= strlen(l
->search_ip
);
1018 /* Completed, s is length of address in HEX */
1022 /* ResetLDAP() - <edui_ldap_t>
1024 * Resets LDAP connection for next search query.
1028 ResetLDAP(edui_ldap_t
*l
)
1030 if (l
== NULL
) return LDAP_ERR_NULL
;
1031 if (!(l
->status
& LDAP_INIT_S
)) return LDAP_ERR_INIT
; /* Not initalized */
1032 if (!(l
->status
& LDAP_OPEN_S
)) return LDAP_ERR_OPEN
; /* Not open */
1033 if (!(l
->status
& LDAP_BIND_S
)) return LDAP_ERR_BIND
; /* Not bound */
1034 if (!(l
->status
& LDAP_PERSIST_S
)) return LDAP_ERR_PERSIST
; /* Not persistent */
1036 /* Cleanup data struct */
1037 if (l
->status
& LDAP_VAL_S
)
1038 l
->status
&= ~(LDAP_VAL_S
);
1039 if (l
->status
& LDAP_SEARCH_S
)
1040 l
->status
&= ~(LDAP_SEARCH_S
);
1041 if (l
->status
& LDAP_IPV4_S
)
1042 l
->status
&= ~(LDAP_IPV4_S
);
1043 if (l
->status
& LDAP_IPV6_S
)
1044 l
->status
&= ~(LDAP_IPV6_S
);
1045 if (l
->lm
!= NULL
) {
1046 ldap_msgfree(l
->lm
);
1049 if (l
->val
!= NULL
) {
1050 ldap_value_free_len(l
->val
);
1053 memset(l
->search_ip
, '\0', sizeof(l
->search_ip
));
1054 *(l
->search_filter
) = '\0';
1055 xstrncpy(l
->search_filter
, edui_conf
.search_filter
, sizeof(l
->search_filter
));
1056 *(l
->userid
) = '\0';
1057 if (!(l
->status
& LDAP_IDLE_S
))
1058 l
->status
|= LDAP_IDLE_S
; /* Set idle mode */
1061 l
->err
= LDAP_SUCCESS
;
1062 return LDAP_ERR_SUCCESS
;
1066 * SearchFilterLDAP() - <edui_ldap_t> <IP> <group>
1068 * Build LDAP Search Filter string and copy to l->search_filter
1072 SearchFilterLDAP(edui_ldap_t
*l
, char *group
)
1076 char bufa
[EDUI_MAXLEN
], bufb
[EDUI_MAXLEN
], bufc
[EDUI_MAXLEN
], bufd
[EDUI_MAXLEN
], bufg
[EDUI_MAXLEN
];
1077 if (l
== NULL
) return LDAP_ERR_NULL
;
1078 if (!(l
->status
& LDAP_INIT_S
)) return LDAP_ERR_INIT
; /* Not initalized */
1079 if (!(l
->status
& LDAP_OPEN_S
)) return LDAP_ERR_OPEN
; /* Not open */
1080 if (!(l
->status
& LDAP_BIND_S
)) return LDAP_ERR_BIND
; /* Not Bound */
1081 if (l
->search_ip
[0] == '\0') return LDAP_ERR_DATA
; /* Search IP is required */
1083 /* Zero out if not already */
1084 memset(bufa
, '\0', sizeof(bufa
));
1085 // using memset() for 'bufa' fixes the 64-bit issue
1091 s
= strlen(l
->search_ip
);
1095 for (i
= 0; i
< s
; i
++) {
1099 bufc
[j
] = l
->search_ip
[i
];
1103 bufc
[j
] = l
->search_ip
[i
];
1108 if (group
== NULL
) {
1109 /* No groupMembership= to add, yay! */
1110 xstrncpy(bufa
, "(&", sizeof(bufa
));
1111 strncat(bufa
, edui_conf
.search_filter
, strlen(edui_conf
.search_filter
));
1112 /* networkAddress */
1113 snprintf(bufb
, sizeof(bufb
), "(|(networkAddress=1\\23%s)", bufc
);
1114 if (l
->status
& LDAP_IPV4_S
) {
1115 int ln
= snprintf(bufd
, sizeof(bufd
), "(networkAddress=8\\23\\00\\00%s)(networkAddress=9\\23\\00\\00%s))", \
1117 strncat(bufb
, bufd
, ln
);
1118 } else if (l
->status
& LDAP_IPV6_S
) {
1119 int ln
= snprintf(bufd
, sizeof(bufd
), "(networkAddress=10\\23\\00\\00%s)(networkAddress=11\\23\\00\\00%s))", \
1121 strncat(bufb
, bufd
, ln
);
1123 strncat(bufb
, ")", 1);
1124 strncat(bufa
, bufb
, strlen(bufb
));
1125 strncat(bufa
, ")", 1);
1127 /* Needs groupMembership= to add... */
1128 xstrncpy(bufa
, "(&(&", sizeof(bufa
));
1129 strncat(bufa
, edui_conf
.search_filter
, strlen(edui_conf
.search_filter
));
1130 /* groupMembership -- NOTE: Squid *MUST* provide "cn=" from squid.conf */
1131 snprintf(bufg
, sizeof(bufg
), "(groupMembership=%s", group
);
1132 if ((l
->basedn
[0] != '\0') && (strstr(group
, l
->basedn
) == NULL
)) {
1133 strncat(bufg
, ",", 1);
1134 strncat(bufg
, l
->basedn
, strlen(l
->basedn
));
1136 strncat(bufg
, ")", 1);
1137 strncat(bufa
, bufg
, strlen(bufg
));
1138 /* networkAddress */
1139 snprintf(bufb
, sizeof(bufb
), "(|(networkAddress=1\\23%s)", bufc
);
1140 if (l
->status
& LDAP_IPV4_S
) {
1141 int ln
= snprintf(bufd
, sizeof(bufd
), "(networkAddress=8\\23\\00\\00%s)(networkAddress=9\\23\\00\\00%s))", \
1143 strncat(bufb
, bufd
, ln
);
1144 } else if (l
->status
& LDAP_IPV6_S
) {
1145 int ln
= snprintf(bufd
, sizeof(bufd
), "(networkAddress=10\\23\\00\\00%s)(networkAddress=11\\23\\00\\00%s))", \
1147 strncat(bufb
, bufd
, ln
);
1149 strncat(bufb
, ")", 1);
1150 strncat(bufa
, bufb
, strlen(bufb
));
1151 strncat(bufa
, "))", 2);
1154 xstrncpy(l
->search_filter
, bufa
, sizeof(l
->search_filter
));
1159 * SearchLDAP() - <edui_ldap_t> <scope> <filter> <attrib>
1161 * Initate LDAP query, under <scope> levels, filtering matches with <filter> and optionally <attrib>
1162 * <attrib> will generally be networkAddress ...
1166 SearchLDAP(edui_ldap_t
*l
, int scope
, char *filter
, char **attrs
)
1169 char ft
[EDUI_MAXLEN
];
1170 if (l
== NULL
) return LDAP_ERR_NULL
;
1171 if ((scope
< 0) || (filter
== NULL
)) return LDAP_ERR_PARAM
; /* If attrs is NULL, then all attrs will return */
1172 if (l
->lp
== NULL
) return LDAP_ERR_POINTER
;
1173 if (!(l
->status
& LDAP_INIT_S
)) return LDAP_ERR_INIT
; /* Not initalized */
1174 if (!(l
->status
& LDAP_OPEN_S
)) return LDAP_ERR_OPEN
; /* Not open */
1175 if (!(l
->status
& LDAP_BIND_S
)) return LDAP_ERR_BIND
; /* Not bound */
1176 if (l
->status
& LDAP_SEARCH_S
) return LDAP_ERR_SEARCHED
; /* Already searching */
1177 if (l
->basedn
[0] == '\0') return LDAP_ERR_DATA
; /* We require a basedn */
1179 ldap_msgfree(l
->lm
); /* Make sure l->lm is empty */
1181 if (filter
== NULL
) /* if filter is NULL, then return ALL networkAddress */
1182 xstrncpy(ft
, "(&(objectClass=User)(networkAddress=*))", sizeof(ft
));
1184 xstrncpy(ft
, filter
, sizeof(ft
));
1186 /* We have a binded connection, with a free l->lm, so let's get this done */
1189 s
= ldap_search_s(l
->lp
, l
->basedn
, LDAP_SCOPE_BASE
, ft
, attrs
, 0, &(l
->lm
));
1192 s
= ldap_search_s(l
->lp
, l
->basedn
, LDAP_SCOPE_ONELEVEL
, ft
, attrs
, 0, &(l
->lm
));
1195 s
= ldap_search_s(l
->lp
, l
->basedn
, LDAP_SCOPE_SUBTREE
, ft
, attrs
, 0, &(l
->lm
));
1198 /* Only search ONE by default */
1199 s
= ldap_search_s(l
->lp
, l
->basedn
, LDAP_SCOPE_ONELEVEL
, ft
, attrs
, 0, &(l
->lm
));
1202 if (s
== LDAP_SUCCESS
) {
1203 l
->status
|= (LDAP_SEARCH_S
); /* Mark as searched */
1205 l
->idle_time
= 0; /* Connection in use, reset idle timer */
1206 l
->num_ent
= ldap_count_entries(l
->lp
, l
->lm
); /* Counted */
1207 return LDAP_ERR_SUCCESS
;
1211 return LDAP_ERR_FAILED
;
1216 * SearchIPLDAP() - <edui_ldap_t>
1218 * Scan LDAP and get all networkAddress Values, and see if they match l->search_ip
1219 * Actual IP matching routine for eDirectory
1223 SearchIPLDAP(edui_ldap_t
*l
)
1229 char bufa
[EDUI_MAXLEN
], bufb
[EDUI_MAXLEN
], hexc
[4];
1231 if (l
== NULL
) return LDAP_ERR_NULL
;
1232 if (l
->lp
== NULL
) return LDAP_ERR_POINTER
;
1233 if (!(l
->status
& LDAP_INIT_S
)) return LDAP_ERR_INIT
; /* Not initalized */
1234 if (!(l
->status
& LDAP_OPEN_S
)) return LDAP_ERR_OPEN
; /* Not open */
1235 if (!(l
->status
& LDAP_BIND_S
)) return LDAP_ERR_BIND
; /* Not bound */
1236 if (!(l
->status
& LDAP_SEARCH_S
)) return LDAP_ERR_NOT_SEARCHED
; /* Not searched */
1237 if (l
->num_ent
<= 0) {
1238 debug("l->num_ent: %d\n", l
->num_ent
);
1239 return LDAP_ERR_DATA
; /* No entries found */
1242 ldap_value_free_len(l
->val
); /* Clear data before populating */
1244 if (l
->status
& LDAP_VAL_S
)
1245 l
->status
&= ~(LDAP_VAL_S
); /* Clear VAL bit */
1246 if (edui_conf
.attrib
[0] == '\0')
1247 xstrncpy(edui_conf
.attrib
, "cn", sizeof(edui_conf
.attrib
)); /* Make sure edui_conf.attrib is set */
1249 /* Sift through entries */
1250 struct berval
**ber
= NULL
;
1251 for (ent
= ldap_first_entry(l
->lp
, l
->lm
); ent
!= NULL
; ent
= ldap_next_entry(l
->lp
, ent
)) {
1252 l
->val
= ldap_get_values_len(l
->lp
, ent
, "networkAddress");
1253 ber
= ldap_get_values_len(l
->lp
, ent
, edui_conf
.attrib
); /* edui_conf.attrib is the <userid> mapping */
1254 if (l
->val
!= NULL
) {
1255 x
= ldap_count_values_len(l
->val
); /* We got x values ... */
1258 /* Display all values */
1259 for (i
= 0; i
< x
; i
++) {
1260 j
= l
->val
[i
]->bv_len
;
1261 memcpy(bufa
, l
->val
[i
]->bv_val
, j
);
1262 z
= BinarySplit(bufa
, j
, '#', bufb
, sizeof(bufb
));
1263 /* BINARY DEBUGGING *
1264 local_printfx("value[%zd]: BinarySplit(", (size_t) i);
1265 for (k = 0; k < z; k++) {
1269 local_printfx("%02X", c);
1271 local_printfx(", ");
1272 for (k = 0; k < (j - z - 1); k++) {
1276 local_printfx("%02X", c);
1278 local_printfx("): %zd\n", (size_t) z);
1279 * BINARY DEBUGGING */
1283 /* IPv4 address (eDirectory 8.7 and below) */
1284 /* bufa is the address, just compare it */
1285 if (!(l
->status
& LDAP_IPV4_S
) || (l
->status
& LDAP_IPV6_S
))
1286 break; /* Not looking for IPv4 */
1287 for (k
= 0; k
< z
; k
++) {
1291 int hlen
= snprintf(hexc
, sizeof(hexc
), "%02X", c
);
1293 xstrncpy(bufb
, hexc
, sizeof(bufb
));
1295 strncat(bufb
, hexc
, hlen
);
1298 /* Compare value with IP */
1299 if (memcmp(l
->search_ip
, bufb
, y
) == 0) {
1300 /* We got a match! - Scan 'ber' for 'cn' values */
1301 z
= ldap_count_values_len(ber
);
1302 for (j
= 0; j
< z
; j
++) {
1303 // broken? xstrncpy(l->userid, ber[j]->bv_val, min(sizeof(l->userid),static_cast<size_t>(ber[j]->bv_len)));
1304 xstrncpy(l
->userid
, ber
[j
]->bv_val
, sizeof(l
->userid
));
1305 /* Using bv_len of min() breaks the result by 2 chars */
1307 ldap_value_free_len(l
->val
);
1309 ldap_value_free_len(ber
);
1312 l
->err
= LDAP_SUCCESS
;
1313 l
->status
&= ~(LDAP_SEARCH_S
);
1314 return LDAP_ERR_SUCCESS
; /* We got our userid */
1316 /* Not matched, continue */
1317 } else if ((j
== 8) || (j
== 9)) {
1318 /* IPv4 (UDP/TCP) address (eDirectory 8.8 and higher) */
1319 /* bufa + 2 is the address (skip 2 digit port) */
1320 if (!(l
->status
& LDAP_IPV4_S
) || (l
->status
& LDAP_IPV6_S
))
1321 break; /* Not looking for IPv4 */
1322 for (k
= 2; k
< z
; k
++) {
1326 int hlen
= snprintf(hexc
, sizeof(hexc
), "%02X", c
);
1328 xstrncpy(bufb
, hexc
, sizeof(bufb
));
1330 strncat(bufb
, hexc
, hlen
);
1333 /* Compare value with IP */
1334 if (memcmp(l
->search_ip
, bufb
, y
) == 0) {
1335 /* We got a match! - Scan 'ber' for 'cn' values */
1336 z
= ldap_count_values_len(ber
);
1337 for (j
= 0; j
< z
; j
++) {
1338 // broken? xstrncpy(l->userid, ber[j]->bv_val, min(sizeof(l->userid),static_cast<size_t>(ber[j]->bv_len)));
1339 xstrncpy(l
->userid
, ber
[j
]->bv_val
, sizeof(l
->userid
));
1340 /* Using bv_len of min() breaks the result by 2 chars */
1342 ldap_value_free_len(l
->val
);
1344 ldap_value_free_len(ber
);
1347 l
->err
= LDAP_SUCCESS
;
1348 l
->status
&= ~(LDAP_SEARCH_S
);
1349 return LDAP_ERR_SUCCESS
; /* We got our userid */
1351 /* Not matched, continue */
1352 } else if ((j
== 10) || (j
== 11)) {
1353 /* IPv6 (UDP/TCP) address (eDirectory 8.8 and higher) */
1354 /* bufa + 2 is the address (skip 2 digit port) */
1355 if (!(l
->status
& LDAP_IPV6_S
))
1356 break; /* Not looking for IPv6 */
1357 for (k
= 2; k
< z
; k
++) {
1361 int hlen
= snprintf(hexc
, sizeof(hexc
), "%02X", c
);
1363 xstrncpy(bufb
, hexc
, sizeof(bufb
));
1365 strncat(bufb
, hexc
, hlen
);
1368 /* Compare value with IP */
1369 if (memcmp(l
->search_ip
, bufb
, y
) == 0) {
1370 /* We got a match! - Scan 'ber' for 'cn' values */
1371 z
= ldap_count_values_len(ber
);
1372 for (j
= 0; j
< z
; j
++) {
1373 // broken? xstrncpy(l->userid, ber[j]->bv_val, min(sizeof(l->userid),static_cast<size_t>(ber[j]->bv_len)));
1374 xstrncpy(l
->userid
, ber
[j
]->bv_val
, sizeof(l
->userid
));
1375 /* Using bv_len of min() breaks the result by 2 chars */
1377 ldap_value_free_len(l
->val
);
1379 ldap_value_free_len(ber
);
1382 l
->err
= LDAP_SUCCESS
;
1383 l
->status
&= ~(LDAP_SEARCH_S
);
1384 return LDAP_ERR_SUCCESS
; /* We got our userid */
1386 /* Not matched, continue */
1389 /* Others are unsupported */
1393 ldap_value_free_len(ber
);
1397 ldap_value_free_len(l
->val
);
1401 ldap_value_free_len(ber
);
1404 /* Attr not found, continue */
1406 /* No entries found using given attr */
1407 if (l
->val
!= NULL
) {
1408 ldap_value_free_len(l
->val
);
1412 ldap_value_free_len(ber
);
1419 if (l
->lm
!= NULL
) {
1420 ldap_msgfree(l
->lm
);
1425 l
->err
= LDAP_NO_SUCH_OBJECT
;
1426 l
->status
&= ~(LDAP_SEARCH_S
);
1427 return LDAP_ERR_NOTFOUND
; /* Not found ... Sorry :) */
1431 * ErrLDAP() - <errno>
1433 * Returns error description of error code
1441 return "Null pointer provided";
1442 case LDAP_ERR_POINTER
:
1443 return "Null LDAP pointer";
1444 case LDAP_ERR_PARAM
:
1445 return "Null or Missing paremeter(s)";
1447 return "LDAP data not initalized";
1449 return "LDAP connection is not active";
1450 case LDAP_ERR_CONNECT
:
1451 return "Unable to connect to LDAP host";
1453 return "LDAP connection is not bound";
1454 case LDAP_ERR_SEARCHED
:
1455 return "LDAP connection has already been searched";
1456 case LDAP_ERR_NOT_SEARCHED
:
1457 return "LDAP connection has not been searched";
1458 case LDAP_ERR_INVALID
:
1459 return "Invalid paremeters";
1461 return "Paremeter is out of bounds";
1462 case LDAP_ERR_PERSIST
:
1463 return "Persistent mode is not active";
1465 return "Required data has not been found";
1466 case LDAP_ERR_NOTFOUND
:
1467 return "Item or object has not been found";
1468 case LDAP_ERR_OTHER
:
1469 return "An unknown error has occured";
1470 case LDAP_ERR_FAILED
:
1471 return "Operation has failed";
1472 case LDAP_ERR_SUCCESS
:
1473 return "Operation is successful";
1475 return "An unknown error has occured";
1480 * SigTrap() - <signal>
1482 * Traps signal codes by number, and gracefully shuts down.
1488 if (!(edui_conf
.mode
& EDUI_MODE_KILL
))
1489 edui_conf
.mode
|= EDUI_MODE_KILL
;
1492 if (edui_ldap
.status
& LDAP_OPEN_S
)
1493 CloseLDAP(&edui_ldap
);
1495 debug("Terminating, Signal: %d\n", s
);
1500 * MainSafe() - <argc> <argv>
1502 * "Safe" version of main()
1506 MainSafe(int argc
, char **argv
)
1508 char bufa
[EDUI_MAXLEN
], bufb
[EDUI_MAXLEN
], *p
= NULL
;
1509 char bufc
[EDUI_MAXLEN
];
1510 char sfmod
[EDUI_MAXLEN
];
1514 struct sigaction sv
;
1518 memset(bufa
, '\0', sizeof(bufa
));
1519 memset(bufb
, '\0', sizeof(bufb
));
1520 memset(bufc
, '\0', sizeof(bufc
));
1521 memset(sfmod
, '\0', sizeof(sfmod
));
1524 xstrncpy(edui_conf
.program
, argv
[0], sizeof(edui_conf
.program
));
1530 for (i
= 1; i
< k
; i
++) {
1531 /* Classic / novelty usage schemes */
1532 if (!strcmp(argv
[i
], "--help")) {
1535 } else if (!strcmp(argv
[i
], "--usage")) {
1538 } else if (!strcmp(argv
[i
], "--version")) {
1541 } else if (argv
[i
][0] == '-') {
1542 s
= strlen(argv
[i
]);
1543 for (j
= 1; j
< s
; j
++) {
1544 switch (argv
[i
][j
]) {
1552 if (!(edui_conf
.mode
& EDUI_MODE_DEBUG
))
1553 edui_conf
.mode
|= EDUI_MODE_DEBUG
; /* Don't set mode more than once */
1554 debug_enabled
= 1; /* Official Squid-3 Debug Mode */
1557 if (!(edui_conf
.mode
& EDUI_MODE_IPV4
) || !(edui_conf
.mode
& EDUI_MODE_IPV6
))
1558 edui_conf
.mode
|= EDUI_MODE_IPV4
; /* Don't set mode more than once */
1561 if (!(edui_conf
.mode
& EDUI_MODE_IPV4
) || !(edui_conf
.mode
& EDUI_MODE_IPV6
))
1562 edui_conf
.mode
|= EDUI_MODE_IPV6
; /* Don't set mode more than once */
1565 if (!(edui_conf
.mode
& EDUI_MODE_TLS
))
1566 edui_conf
.mode
|= EDUI_MODE_TLS
; /* Don't set mode more than once */
1569 if (!(edui_conf
.mode
& EDUI_MODE_PERSIST
))
1570 edui_conf
.mode
|= EDUI_MODE_PERSIST
; /* Don't set mode more than once */
1573 i
++; /* Set LDAP version */
1574 if (argv
[i
] != NULL
) {
1575 edui_conf
.ver
= atoi(argv
[i
]);
1576 if (edui_conf
.ver
< 1)
1578 else if (edui_conf
.ver
> 3)
1581 local_printfx("No parameters given for 'v'.\n");
1587 i
++; /* Set Persistent timeout */
1588 if (argv
[i
] != NULL
) {
1589 edui_conf
.persist_timeout
= atoi(argv
[i
]);
1590 if (edui_conf
.persist_timeout
< 0)
1591 edui_conf
.persist_timeout
= 0;
1593 local_printfx("No parameters given for 't'.\n");
1599 i
++; /* Set Base DN */
1600 if (argv
[i
] != NULL
)
1601 xstrncpy(edui_conf
.basedn
, argv
[i
], sizeof(edui_conf
.basedn
));
1603 local_printfx("No parameters given for 'b'.\n");
1609 i
++; /* Set Hostname */
1610 if (argv
[i
] != NULL
)
1611 xstrncpy(edui_conf
.host
, argv
[i
], sizeof(edui_conf
.host
));
1613 local_printfx("No parameters given for 'H'.\n");
1620 if (argv
[i
] != NULL
)
1621 edui_conf
.port
= atoi(argv
[i
]);
1623 local_printfx("No parameters given for 'p'.\n");
1629 i
++; /* Set Bind DN */
1630 if (argv
[i
] != NULL
)
1631 xstrncpy(edui_conf
.dn
, argv
[i
], sizeof(edui_conf
.dn
));
1633 local_printfx("No parameters given for 'D'.\n");
1639 i
++; /* Set Bind PWD */
1640 if (argv
[i
] != NULL
)
1641 xstrncpy(edui_conf
.passwd
, argv
[i
], sizeof(edui_conf
.passwd
));
1643 local_printfx("No parameters given for 'W'.\n");
1649 i
++; /* Set Search Filter */
1650 if (argv
[i
] != NULL
)
1651 xstrncpy(edui_conf
.search_filter
, argv
[i
], sizeof(edui_conf
.search_filter
));
1653 local_printfx("No parameters given for 'F'.\n");
1659 if (!(edui_conf
.mode
& EDUI_MODE_GROUP
))
1660 edui_conf
.mode
|= EDUI_MODE_GROUP
; /* Don't set mode more than once */
1663 i
++; /* Set Scope Level */
1664 if (argv
[i
] != NULL
) {
1665 if (!strncmp(argv
[i
], "base", 4))
1666 edui_conf
.scope
= 0;
1667 else if (!strncmp(argv
[i
], "one", 4))
1668 edui_conf
.scope
= 1;
1669 else if (!strncmp(argv
[i
], "sub", 4))
1670 edui_conf
.scope
= 2;
1672 edui_conf
.scope
= 1; /* Default is 'one' */
1674 local_printfx("No parameters given for 's'.\n");
1680 i
++; /* Set Search Attribute */
1681 if (argv
[i
] != NULL
) {
1682 xstrncpy(edui_conf
.attrib
, argv
[i
], sizeof(edui_conf
.attrib
));
1684 local_printfx("No parameters given for 'u'.\n");
1689 case '-': /* We got a second '-' ... ignore */
1692 local_printfx("Invalid parameter - '%c'.\n", argv
[i
][j
]);
1697 /* Incorrect parameter, display usage */
1704 /* Set predefined required paremeters if none are given, localhost:LDAP_PORT, etc */
1705 if (edui_conf
.host
[0] == '\0') /* Default to localhost */
1706 xstrncpy(edui_conf
.host
, "localhost", sizeof(edui_conf
.host
));
1707 if (edui_conf
.port
< 0)
1708 edui_conf
.port
= LDAP_PORT
; /* Default: LDAP_PORT */
1709 if ((edui_conf
.mode
& EDUI_MODE_IPV4
) && (edui_conf
.mode
& EDUI_MODE_IPV6
))
1710 edui_conf
.mode
&= ~(EDUI_MODE_IPV6
); /* Default to IPv4 */
1711 if (edui_conf
.ver
< 0)
1713 if (!(edui_conf
.mode
& EDUI_MODE_TLS
))
1714 edui_conf
.mode
|= EDUI_MODE_TLS
; /* eDirectory requires TLS mode */
1715 if ((edui_conf
.mode
& EDUI_MODE_TLS
) && (edui_conf
.ver
< 3))
1716 edui_conf
.ver
= 3; /* TLS requires version 3 */
1717 if (edui_conf
.persist_timeout
< 0)
1718 edui_conf
.persist_timeout
= 600; /* Default: 600 seconds (10 minutes) */
1719 if (edui_conf
.scope
< 0)
1720 edui_conf
.scope
= 1; /* Default: one */
1721 if (edui_conf
.search_filter
[0] == '\0')
1722 xstrncpy(edui_conf
.search_filter
, "(&(objectclass=User)(networkAddress=*))", sizeof(edui_conf
.search_filter
));
1723 if (edui_conf
.attrib
[0] == '\0')
1724 xstrncpy(edui_conf
.attrib
, "cn", sizeof(edui_conf
.attrib
));
1725 if (edui_conf
.basedn
[0] == '\0') {
1726 local_printfx("FATAL: No '-b' option provided (Base DN).\n");
1730 /* Trap the following signals */
1731 sigemptyset(&sv
.sa_mask
);
1732 sv
.sa_handler
= SigTrap
;
1733 sigaction(SIGTERM
, &sv
, NULL
);
1734 sv
.sa_handler
= SigTrap
;
1735 sigaction(SIGHUP
, &sv
, NULL
);
1736 sv
.sa_handler
= SigTrap
;
1737 sigaction(SIGABRT
, &sv
, NULL
);
1738 sv
.sa_handler
= SigTrap
;
1739 sigaction(SIGINT
, &sv
, NULL
);
1740 sv
.sa_handler
= SigTrap
;
1741 sigaction(SIGSEGV
, &sv
, NULL
);
1744 /* Done with arguments */
1746 /* Set elap timer */
1749 /* Main loop -- Waits for stdin input before action */
1750 while (fgets(bufa
, sizeof(bufa
), stdin
) != NULL
) {
1751 if (edui_conf
.mode
& EDUI_MODE_KILL
)
1755 /* Elapse seconds */
1756 edui_elap
= edui_now
- t
;
1761 /* BINARY DEBUGGING *
1762 local_printfx("while() -> bufa[%zd]: %s", k, bufa);
1763 for (i = 0; i < k; i++)
1764 local_printfx("%02X", bufa[i]);
1765 local_printfx("\n");
1766 * BINARY DEBUGGING */
1767 /* Check for CRLF */
1768 p
= strchr(bufa
, '\n');
1771 p
= strchr(bufa
, '\r');
1774 p
= strchr(bufa
, ' ');
1776 /* No space given, but group string is required --> ERR */
1777 if ((edui_conf
.mode
& EDUI_MODE_GROUP
) && (p
== NULL
)) {
1778 debug("while() -> Search group is missing. (required)\n");
1779 local_printfx("ERR (Search Group Required)\n");
1784 /* Open LDAP connection */
1785 if (!(edui_ldap
.status
& LDAP_INIT_S
)) {
1786 InitLDAP(&edui_ldap
);
1787 debug("InitLDAP() -> %s\n", ErrLDAP(LDAP_ERR_SUCCESS
));
1788 if (edui_conf
.mode
& EDUI_MODE_PERSIST
) /* Setup persistant mode */
1789 edui_ldap
.status
|= LDAP_PERSIST_S
;
1791 if ((edui_ldap
.status
& LDAP_IDLE_S
) && (edui_elap
> 0)) {
1792 edui_ldap
.idle_time
= edui_ldap
.idle_time
+ edui_elap
;
1794 if ((edui_ldap
.status
& LDAP_PERSIST_S
) && (edui_ldap
.status
& LDAP_IDLE_S
) && (edui_ldap
.idle_time
> edui_conf
.persist_timeout
)) {
1795 debug("while() -> Connection timed out after %d seconds\n", (int)(edui_ldap
.idle_time
));
1796 x
= CloseLDAP(&edui_ldap
);
1797 debug("CloseLDAP(-) -> %s\n", ErrLDAP(x
));
1800 if (!(edui_ldap
.status
& LDAP_OPEN_S
)) {
1801 x
= OpenLDAP(&edui_ldap
, edui_conf
.host
, edui_conf
.port
);
1802 if (x
!= LDAP_ERR_SUCCESS
) {
1803 /* Failed to connect */
1804 debug("OpenLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x
), ldap_err2string(edui_ldap
.err
));
1806 debug("OpenLDAP(-, %s, %d) -> %s\n", edui_conf
.host
, edui_conf
.port
, ErrLDAP(x
));
1807 x
= SetVerLDAP(&edui_ldap
, edui_conf
.ver
);
1808 if (x
!= LDAP_ERR_SUCCESS
) {
1809 /* Failed to set version */
1810 debug("SetVerLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x
), ldap_err2string(edui_ldap
.err
));
1812 debug("SetVerLDAP(-, %d) -> %s\n", edui_conf
.ver
, ErrLDAP(x
));
1816 if (!(edui_ldap
.status
& LDAP_BIND_S
) && (edui_conf
.mode
& EDUI_MODE_TLS
)) {
1818 x
= BindLDAP(&edui_ldap
, edui_conf
.dn
, edui_conf
.passwd
, LDAP_AUTH_TLS
);
1819 if (x
!= LDAP_ERR_SUCCESS
) {
1820 /* Unable to bind */
1821 debug("BindLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x
), ldap_err2string(edui_ldap
.err
));
1822 local_printfx("ERR (BindLDAP: %s - %s)\n", ErrLDAP(x
), ldap_err2string(edui_ldap
.err
));
1825 debug("BindLDAP(-, %s, %s, (LDAP_AUTH_TLS)) -> %s\n", edui_conf
.dn
, edui_conf
.passwd
, ErrLDAP(x
));
1826 } else if (!(edui_ldap
.status
& LDAP_BIND_S
)) {
1827 if (edui_conf
.dn
[0] != '\0') {
1828 /* Simple binding - using dn / passwd for authorization */
1829 x
= BindLDAP(&edui_ldap
, edui_conf
.dn
, edui_conf
.passwd
, LDAP_AUTH_SIMPLE
);
1830 if (x
!= LDAP_ERR_SUCCESS
) {
1831 /* Unable to bind */
1832 debug("BindLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x
), ldap_err2string(edui_ldap
.err
));
1833 local_printfx("ERR (BindLDAP: %s - %s)\n", ErrLDAP(x
), ldap_err2string(edui_ldap
.err
));
1836 debug("BindLDAP(-, %s, %s, (LDAP_AUTH_SIMPLE)) -> %s\n", edui_conf
.dn
, edui_conf
.passwd
, ErrLDAP(x
));
1838 /* Anonymous binding */
1839 x
= BindLDAP(&edui_ldap
, edui_conf
.dn
, edui_conf
.passwd
, LDAP_AUTH_NONE
);
1840 if (x
!= LDAP_ERR_SUCCESS
) {
1841 /* Unable to bind */
1842 debug("BindLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x
), ldap_err2string(edui_ldap
.err
));
1843 local_printfx("ERR (BindLDAP: %s - %s)\n", ErrLDAP(x
), ldap_err2string(edui_ldap
.err
));
1846 debug("BindLDAP(-, -, -, (LDAP_AUTH_NONE)) -> %s\n", ErrLDAP(x
));
1850 if (edui_ldap
.status
& LDAP_PERSIST_S
) {
1851 x
= ResetLDAP(&edui_ldap
);
1852 if (x
!= LDAP_ERR_SUCCESS
) {
1853 /* Unable to reset */
1854 debug("ResetLDAP() -> %s\n", ErrLDAP(x
));
1856 debug("ResetLDAP() -> %s\n", ErrLDAP(x
));
1858 if (x
!= LDAP_ERR_SUCCESS
) {
1859 /* Everything failed --> ERR */
1860 debug("while() -> %s (LDAP: %s)\n", ErrLDAP(x
), ldap_err2string(edui_ldap
.err
));
1861 CloseLDAP(&edui_ldap
);
1862 local_printfx("ERR (General Failure: %s)\n", ErrLDAP(x
));
1866 /* If we got a group string, split it */
1869 debug("StringSplit(%s, ' ', %s, %zd)\n", bufa
, bufb
, sizeof(bufb
));
1870 i
= StringSplit(bufa
, ' ', bufb
, sizeof(bufb
));
1872 debug("StringSplit(%s, %s) done. Result: %zd\n", bufa
, bufb
, i
);
1873 /* Got a group to match against */
1874 x
= ConvertIP(&edui_ldap
, bufb
);
1876 debug("ConvertIP() -> %s\n", ErrLDAP(x
));
1877 local_printfx("ERR (ConvertIP: %s)\n", ErrLDAP(x
));
1880 debug("ConvertIP(-, %s) -> Result[%d]: %s\n", bufb
, x
, edui_ldap
.search_ip
);
1881 x
= SearchFilterLDAP(&edui_ldap
, bufa
);
1883 debug("SearchFilterLDAP() -> %s\n", ErrLDAP(x
));
1884 local_printfx("ERR (SearchFilterLDAP: %s)\n", ErrLDAP(x
));
1888 debug("SearchFilterLDAP(-, %s) -> Length: %u\n", bufa
, x
);
1889 x
= SearchLDAP(&edui_ldap
, edui_ldap
.scope
, edui_ldap
.search_filter
, (char **) &search_attrib
);
1890 if (x
!= LDAP_ERR_SUCCESS
) {
1891 debug("SearchLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x
), ldap_err2string(edui_ldap
.err
));
1892 local_printfx("ERR (SearchLDAP: %s)\n", ErrLDAP(x
));
1895 debug("SearchLDAP(-, %d, %s, -) -> %s\n", edui_conf
.scope
, edui_ldap
.search_filter
, ErrLDAP(x
));
1896 x
= SearchIPLDAP(&edui_ldap
);
1897 if (x
!= LDAP_ERR_SUCCESS
) {
1898 debug("SearchIPLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x
), ldap_err2string(edui_ldap
.err
));
1899 local_printfx("ERR (SearchIPLDAP: %s)\n", ErrLDAP(x
));
1901 debug("SearchIPLDAP(-, %s) -> %s\n", edui_ldap
.userid
, ErrLDAP(x
));
1902 local_printfx("OK user=%s\n", edui_ldap
.userid
); /* Got userid --> OK user=<userid> */
1905 /* Clear for next query */
1906 memset(bufc
, '\0', sizeof(bufc
));
1910 debug("StringSplit() -> Error: %Zu\n", i
);
1911 local_printfx("ERR (StringSplit Error %d)\n", i
);
1914 /* No group to match against, only an IP */
1915 x
= ConvertIP(&edui_ldap
, bufa
);
1917 debug("ConvertIP() -> %s\n", ErrLDAP(x
));
1918 local_printfx("ERR (ConvertIP: %s)\n", ErrLDAP(x
));
1920 debug("ConvertIP(-, %s) -> Result[%d]: %s\n", bufa
, x
, edui_ldap
.search_ip
);
1922 x
= SearchFilterLDAP(&edui_ldap
, NULL
);
1924 debug("SearchFilterLDAP() -> %s\n", ErrLDAP(x
));
1925 local_printfx("ERR (SearchFilterLDAP: %s)\n", ErrLDAP(x
));
1928 debug("SearchFilterLDAP(-, NULL) -> Length: %u\n", x
);
1929 x
= SearchLDAP(&edui_ldap
, edui_ldap
.scope
, edui_ldap
.search_filter
, (char **) &search_attrib
);
1930 if (x
!= LDAP_ERR_SUCCESS
) {
1931 debug("SearchLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x
), ldap_err2string(x
));
1932 local_printfx("ERR (SearchLDAP: %s)\n", ErrLDAP(x
));
1935 debug("SearchLDAP(-, %d, %s, -) -> %s\n", edui_conf
.scope
, edui_ldap
.search_filter
, ErrLDAP(x
));
1936 x
= SearchIPLDAP(&edui_ldap
);
1937 if (x
!= LDAP_ERR_SUCCESS
) {
1938 debug("SearchIPLDAP() -> %s (LDAP: %s)\n", ErrLDAP(x
), ldap_err2string(edui_ldap
.err
));
1939 local_printfx("ERR (SearchIPLDAP: %s)\n", ErrLDAP(x
));
1941 debug("SearchIPLDAP(-, %s) -> %s\n", edui_ldap
.userid
, ErrLDAP(x
));
1942 local_printfx("OK user=%s\n", edui_ldap
.userid
); /* Got a userid --> OK user=<userid> */
1946 /* Clear for next query */
1947 memset(bufc
, '\0', sizeof(bufc
));
1951 /* Clear buffer and close for next data, if not persistent */
1953 memset(bufa
, '\0', sizeof(bufa
));
1954 if (!(edui_ldap
.status
& LDAP_PERSIST_S
)) {
1955 x
= CloseLDAP(&edui_ldap
);
1956 debug("CloseLDAP(-) -> %s\n", ErrLDAP(x
));
1960 debug("Terminating.\n");
1964 /* "main()" - function */
1966 main(int argc
, char **argv
)
1969 x
= MainSafe(argc
, argv
);