Автор: vlary
Дата сообщения: 23.03.2011 23:49
ginger Я еще не так давно использовал идентефикацию юзеров в АД непосредственно через LDAP. Для этого использовал такую программу написанную на Си:
[more=Код программы]
/*
* squid_ad_auth: authentication via ldap for squid proxy server
*/
#define LDAP_DEPRECATED 1
#define LDAP_UNICODE 0
#define MAX_USERS 128
#include <sys/time.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
/* Some tricks to allow dynamic bind with ldap_start_tls_s entry point at
* run time.
*/
#include <lber.h>
#include <ldap.h>
#define PROGRAM_NAME "squid_ad_auth"
#define xisspace(x) isspace((unsigned char)x)
/* Global options */
struct accnt
{
char name[16];
char pwtext[16];
};
struct accnt users[MAX_USERS];
static const char *basedn;
static const char *searchfilter = NULL;
static const char *binddn = NULL;
static const char *bindpasswd = NULL;
static const char *userattr = "cn";
static const char *passwdattr = NULL;
static int searchscope = LDAP_SCOPE_SUBTREE;
static int cached = 0;
static int bind_once = 0;
static int noreferrals = 0;
static int aliasderef = LDAP_DEREF_NEVER;
static int connect_timeout = 0;
static int timelimit = LDAP_NO_LIMIT;
static int debug = 0;
/* Added for TLS support and version 3 */
static int use_tls = 0;
static int version = -1;
static int checkcache(char *user, char *password)
{
int n;
for(n=0;n<cached;n++)
{
if(strcmp(user,users[n].name)==0 && strcmp(password,users[n].pwtext)==0)
return n;
}
return -1;
}
/* Yuck.. we need to glue to different versions of the API */
#ifndef LDAP_NO_ATTRS
#define LDAP_NO_ATTRS "1.1"
#endif
/*
* RFC 1738 defines that these characters should be escaped, as well
* any non-US-ASCII character or anything between 0x00 - 0x1F.
*/
static char rfc1738_unsafe_chars[] =
{
(char) 0x3C, /* < */
(char) 0x3E, /* > */
(char) 0x22, /* " */
(char) 0x23, /* # */
#if 0 /* done in code */
(char) 0x25, /* % */
#endif
(char) 0x7B, /* { */
(char) 0x7D, /* } */
(char) 0x7C, /* | */
(char) 0x5C, /* \ */
(char) 0x5E, /* ^ */
(char) 0x7E, /* ~ */
(char) 0x5B, /* [ */
(char) 0x5D, /* ] */
(char) 0x60, /* ` */
(char) 0x27, /* ' */
(char) 0x20 /* space */
};
static char rfc1738_reserved_chars[] =
{
(char) 0x3b, /* ; */
(char) 0x2f, /* / */
(char) 0x3f, /* ? */
(char) 0x3a, /* : */
(char) 0x40, /* @ */
(char) 0x3d, /* = */
(char) 0x26 /* & */
};
void xfree(void *s)
{
if(s!=NULL)
free(s);
}
/*
* xcalloc() - same as calloc(3). Used for portability.
* Never returns NULL; fatal on error.
*/
void *
xcalloc(size_t n, size_t sz)
{
void *p;
if (n < 1)
n = 1;
if (sz < 1)
sz = 1;
if ((p = calloc(n, sz)) == NULL) {
perror("xcalloc");
exit(1);
}
return (p);
}
/*
* rfc1738_escape - Returns a static buffer contains the RFC 1738
* compliant, escaped version of the given url.
*/
static char *
rfc1738_do_escape(const char *url, int encode_reserved)
{
static char *buf;
static size_t bufsize = 0;
const char *p;
char *q;
unsigned int i, do_escape;
if (buf == NULL || strlen(url) * 3 > bufsize) {
xfree(buf);
bufsize = strlen(url) * 3 + 1;
buf = xcalloc(bufsize, 1);
}
for (p = url, q = buf; *p != '\0'; p++, q++) {
do_escape = 0;
/* RFC 1738 defines these chars as unsafe */
for (i = 0; i < sizeof(rfc1738_unsafe_chars); i++) {
if (*p == rfc1738_unsafe_chars[i]) {
do_escape = 1;
break;
}
}
/* Handle % separately */
if (encode_reserved >= 0 && *p == '%')
do_escape = 1;
/* RFC 1738 defines these chars as reserved */
for (i = 0; i < sizeof(rfc1738_reserved_chars) && encode_reserved > 0; i
++) {
if (*p == rfc1738_reserved_chars[i]) {
do_escape = 1;
break;
}
}
/* RFC 1738 says any control chars (0x00-0x1F) are encoded */
if ((unsigned char) *p <= (unsigned char) 0x1F) {
do_escape = 1;
}
/* RFC 1738 says 0x7f is encoded */
if (*p == (char) 0x7F) {
do_escape = 1;
}
/* RFC 1738 says any non-US-ASCII are encoded */
if (((unsigned char) *p >= (unsigned char) 0x80)) {
do_escape = 1;
}
/* Do the triplet encoding, or just copy the char */
/* note: we do not need snprintf here as q is appropriately
* allocated - KA */
if (do_escape == 1) {
(void) sprintf(q, "%%%02X", (unsigned char) *p);
q += sizeof(char) * 2;
} else {
*q = *p;
}
}
*q = '\0';
return (buf);
}
/*
* rfc1738_escape - Returns a static buffer that contains the RFC
* 1738 compliant, escaped version of the given url.
*/
char *
rfc1738_escape(const char *url)
{
return rfc1738_do_escape(url, 0);
}
/*
* rfc1738_escape_unescaped - Returns a static buffer that contains
* the RFC 1738 compliant, escaped version of the given url.
*/
char *
rfc1738_escape_unescaped(const char *url)
{
return rfc1738_do_escape(url, -1);
}
/*
* rfc1738_escape_part - Returns a static buffer that contains the
* RFC 1738 compliant, escaped version of the given url segment.
*/
char *
rfc1738_escape_part(const char *url)
{
return rfc1738_do_escape(url, 1);
}
/*
* rfc1738_unescape() - Converts escaped characters (%xy numbers) in
* given the string. %% is a %. %ab is the 8-bit hexadecimal number "ab"
*/
void
rfc1738_unescape(char *s)
{
char hexnum[3];
int i, j; /* i is write, j is read */
unsigned int x;
for (i = j = 0; s[j]; i++, j++) {
s[i] = s[j];
if (s[i] != '%')
continue;
if (s[j + 1] == '%') { /* %% case */
j++;
continue;
}
if (s[j + 1] && s[j + 2]) {
if (s[j + 1] == '0' && s[j + 2] == '0') { /* %00 case */
j += 2;
continue;
}
hexnum[0] = s[j + 1];
hexnum[1] = s[j + 2];
hexnum[2] = '\0';
if (1 == sscanf(hexnum, "%x", &x)) {
s[i] = (char) (0x0ff & x);
j += 2;
}
}
}
s[i] = '\0';
}
#if defined(LDAP_API_VERSION) && LDAP_API_VERSION > 1823
static int
squid_ldap_errno(LDAP * ld)
{
int err = 0;
ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err);
return err;
}
static void
squid_ldap_set_aliasderef(LDAP * ld, int deref)
{
ldap_set_option(ld, LDAP_OPT_DEREF, &deref);
}
static void
squid_ldap_set_referrals(LDAP * ld, int referrals)
{
int *value = referrals ? LDAP_OPT_ON : LDAP_OPT_OFF;
ldap_set_option(ld, LDAP_OPT_REFERRALS, value);
}
static void
squid_ldap_set_timelimit(LDAP * ld, int timelimit)
{
ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &timelimit);
}
static void
squid_ldap_set_connect_timeout(LDAP * ld, int timelimit)
{
#if defined(LDAP_OPT_NETWORK_TIMEOUT)
struct timeval tv;
tv.tv_sec = timelimit;
tv.tv_usec = 0;
ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
#elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
timelimit *= 1000;
ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timelimit);
#endif
}
static void
squid_ldap_memfree(char *p)
{
ldap_memfree(p);
}
#else
static int
squid_ldap_errno(LDAP * ld)
{
return ld->ld_errno;
}
static void
squid_ldap_set_aliasderef(LDAP * ld, int deref)
{
ld->ld_deref = deref;
}
static void
squid_ldap_set_referrals(LDAP * ld, int referrals)
{
if (referrals)
ld->ld_options |= ~LDAP_OPT_REFERRALS;
else
ld->ld_options &= ~LDAP_OPT_REFERRALS;
}
static void
squid_ldap_set_timelimit(LDAP * ld, int timelimit)
{
ld->ld_timelimit = timelimit;
}
static void
squid_ldap_set_connect_timeout(LDAP * ld, int timelimit)
{
fprintf(stderr, "Connect timeouts not supported in your LDAP library\n");
}
static void
squid_ldap_memfree(char *p)
{
free(p);
}
#endif
static LDAP *
open_ldap_connection(const char *ldapServer, int port)
{
LDAP *ld = NULL;
if ((ld = ldap_init(ldapServer, port)) == NULL) {
fprintf(stderr, "\nUnable to connect to LDAP server:%s port:%d\n",
ldapServer, port);
exit(1);
}
if (connect_timeout)
squid_ldap_set_connect_timeout(ld, connect_timeout);
#ifdef LDAP_VERSION3
if (version == -1) {
version = LDAP_VERSION2;
}
if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version) != LDAP_SUCCESS
) {
fprintf(stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n",
version);
exit(1);
}
#endif
squid_ldap_set_timelimit(ld, timelimit);
squid_ldap_set_referrals(ld, !noreferrals);
squid_ldap_set_aliasderef(ld, aliasderef);
return ld;
}
/* Check the userid & password.
* Return 0 on success, 1 on failure
*/
static int
checkLDAP(const char *userid, const char *password, const char *ldapServer, int
port)
{
char dn[1024];
int ret = 0;
LDAP *bind_ld = NULL;
if (!*password) {
/* LDAP can't bind with a blank password. Seen as "anonymous"
* and always granted access
*/
if (debug)
fprintf(stderr, "Blank password given\n");
return 1;
}
snprintf(dn, sizeof(dn), "CN=%s,OU=your_unit,DC=your_domain,DC=com", userid);
if (debug)
fprintf(stderr, "Attempting to authenticate user '%s'\n", dn);
bind_ld = open_ldap_connection(ldapServer, port);
if(bind_ld==NULL)
{
if (debug)
fprintf(stderr, "Cannot connect to server %s \n",ldapServer);
return 1;
}
if (ldap_simple_bind_s(bind_ld, dn, password) != LDAP_SUCCESS)
ret = 1;
ldap_unbind(bind_ld);
bind_ld = NULL;
return ret;
}
/* Make a sanity check on the username to reject oddly typed names */
static int
validUsername(const char *user)
{
const unsigned char *p = (const unsigned char *) user;
/* Leading whitespace? */
if (xisspace(p[0]))
return 0;
while (p[0] && p[1]) {
if (xisspace(p[0])) {
/* More than one consequitive space? */
if (xisspace(p[1]))
return 0;
/* or odd space type character used? */
if (p[0] != ' ')
return 0;
}
p++;
}
/* Trailing whitespace? */
if (xisspace(p[0]))
return 0;
return 1;
}
int
main(int argc, char **argv)
{
char buf[1024];
char *user, *passwd;
char ldapServer[32];
int tryagain;
int port = LDAP_PORT;
setbuf(stdout, NULL);
if (argc > 2)
{
strncpy(ldapServer,argv[2],31);
debug++;
}
else if(argc==2)
{
strncpy(ldapServer,argv[1],31);
}
else {
fprintf(stderr, "Usage: " PROGRAM_NAME " [-d] ldap_server_name\n");
exit(1);
}
while (fgets(buf, sizeof(buf), stdin) != NULL) {
user = strtok(buf, " \r\n");
passwd = strtok(NULL, "\r\n");
if (!user || !passwd || !passwd[0]) {
printf("ERR\n");
continue;
}
if (debug)
fprintf(stderr, "User: %s Password: %s \n",user,passwd );
rfc1738_unescape(user);
rfc1738_unescape(passwd);
if (!validUsername(user)) {
printf("ERR Bad user name\n");
continue;
}
if(checkcache(user,passwd)>=0)
{
if (debug)
fprintf(stderr, "User %s found in cache\n",user );
printf("OK\n");
continue;
}
if (checkLDAP(user, passwd, ldapServer, port) != 0) {
printf("ERR\n");
} else {
printf("OK\n");
if(cached>=MAX_USERS)
continue;
strncpy(users[cached].name,user,15);
strncpy(users[cached].pwtext,passwd,15);
cached++;
}
}
return 0;
}
[/more]
Для компиляции кода нужны библиотеки liblber и libldap, они обычно идут с самбой.
Все работало очень четко, быстро и пристойно.