hello all,
This is my first contributation on this mailing list.
I have setup Binc IMAP for a environment in which users are stored in a
openldap directory, so are the uid and gid.
Since I couldn't find a implementation of checkpassword that retrieved
the uid/gid from the directory.
So I decided to modify the checkpassword-ldap program.
And here it is, mostly for refence material and hopefully some
constructive comments.
You can compile it using:
#gcc checkpassword-ldap.c -o chkpassword-ldap -lldap
This is also the first C program I write, so tips,comments, flames for
obvious errors/faults are appreciated.
If there are more people who need it, I would be willing to improve the
program and practice some c at the same time.
With regards,
--
Jos Houtman <[EMAIL PROTECTED]>
/*
* This is an checkpassword implimentation which also retrieves the UID and GID
* from the ldap database. Code is borrowed from the checkpassword-ldap
* implementation (see below).
*
* Jos <[EMAIL PROTECTED]>
*
* checkpassword-ldap
*
* checkpassword implementation that searches an LDAP database
* for all the necessary parameter.
*
* Copyright (C) 2003 Scott James Remnant <[EMAIL PROTECTED]>.
* Copyright (C) 2004 Herve Commowick <[EMAIL PROTECTED]>
*
*/
#include <sys/types.h>
#include <grp.h>
#include <pwd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ldap.h>
/* Customise these to change the behaviour.
* LDAP_HOST hostname of your LDAP server
* LDAP_BASE base under which entry must exist
* LDAP_BIND_DN dn of the account who has the good permissions to request search
* LDAP_BIND_PASSWD password of the account who has the good permissions to request search
*
* LDAP_SCOPE search scope relative to base
* LDAP_FILTER filter to use, must contain one %s which is replaced with the login name.
*
* LDAP_LOGIN_FIELD name of field containing username
* LDAP_UID_FIELD name of the field containing the system uid
* LDAP_GID_FIELD name of the field containing the system gid
* LDAP_HOME_FIELD name of field containing the directory of the mailbox
*/
#define LDAP_HOST "localhost"
#define LDAP_BASE "dc=caillte,dc=net"
#define LDAP_BIND_DN "ou=courierImap,ou=System,dc=caillte,dc=net"
#define LDAP_BIND_PASSWD "xxx"
#define LDAP_SCOPE LDAP_SCOPE_SUBTREE
#define LDAP_FILTER "(&(uid=%s)(&(accountStatus=active)(objectClass=qmailUser)))"
#define LDAP_LOGIN_FIELD "uid"
#define LDAP_UID_FIELD "uidNumber"
#define LDAP_GID_FIELD "gidNumber"
#define LDAP_HOME_FIELD "mailMessageStore"
#define MAILDIR_PREFIX ""
#define MAILDIR_POSTFIX "../"
#define DEBUG 0
#define PROTOCOL_LEN 512
static int protocol_fd = 3;
char up[PROTOCOL_LEN];
char *prog, *password, *homeparam, *username, **values;
unsigned int userId;
gid_t groupId;
int main (int argc, char *argv[])
{
FILE *protocol;
int uplen, i;
prog = argv[0];
if (DEBUG == 1) {
printf("Reading username/password\n" );
}
protocol = fdopen(protocol_fd, "r");
if (protocol == NULL) {
fprintf(stderr, "%s: error opening porotocol fd (%d): %s\n",
prog, protocol_fd, strerror(errno));
return 2;
}
uplen = fread(up, 1, PROTOCOL_LEN, protocol);
if (uplen == 0) {
fprintf(stderr, "%s: bad protocol, zero bytes read\n", prog);
return 2;
}
i = 0;
username = up + i;
while (up[i++]) {
if (i >= uplen) {
fprintf(stderr, "%s: bad protocol, no username\n",
prog);
return 2;
}
}
password = up + i;
while (up[i++]) {
if (i >= uplen) {
fprintf(stderr, "%s: bad protocol, no password\n",
prog);
return 2;
}
}
if (DEBUG)
printf("username: %s, password: %s \n", username, password);
char *attrs[] = { NULL };
char *filter, *dn;
LDAP *ld;
LDAPMessage *res, *entry;
int ret;
ld = ldap_init(LDAP_HOST, LDAP_PORT);
if (!ld) {
fprintf(stderr, "%s: unable to initialise ldap connection\n",
prog);
return 111;
}
if (DEBUG)
printf("Connected, Binding....\n");
ret = ldap_simple_bind_s(ld, LDAP_BIND_DN, LDAP_BIND_PASSWD);
if (ret){
fprintf(stderr, "%s: unable to Bind to ldap server: %s\n",
prog, ldap_err2string(ret));
return 111;
}
if (DEBUG)
printf("Bind Succesfull, Searching....\n");
filter = malloc(sizeof(LDAP_FILTER) + strlen(username));
sprintf(filter, LDAP_FILTER, username);
ret = ldap_search_s(ld, LDAP_BASE, LDAP_SCOPE, filter, attrs, 0, &res);
if (ret) {
fprintf(stderr, "%s: ldap search failed: %s\n", prog,
ldap_err2string(ret));
return 1;
}
//we found our user
entry = ldap_first_entry(ld, res);
if (!entry){
fprintf(stderr, "%s: No entry returned: \n", prog);
return 1;
}
//get its DN so we can rebind to authenticate him/her
dn = ldap_get_dn(ld, res);
//try to get the necessary attributes, so we dont have to do it later
values = ldap_get_values(ld, entry, LDAP_HOME_FIELD);
if (values && values[0])
{
homeparam = malloc(strlen(MAILDIR_PREFIX) + strlen(values[0]) + strlen(MAILDIR_POSTFIX) + 1);
strcpy(homeparam,MAILDIR_PREFIX);
strcat(homeparam,values[0]);
strcat(homeparam,MAILDIR_POSTFIX);
}
values = ldap_get_values(ld, entry, LDAP_UID_FIELD);
if (values && values[0])
{
userId = atoi(values[0]);
}
values = ldap_get_values(ld, entry, LDAP_GID_FIELD);
if (values && values[0])
{
groupId = atoi(values[0]);
}
if (DEBUG) printf("userattribute - homeparam: %s - %u/%u \n", homeparam, userId, groupId);
ldap_msgfree(res);
ret = ldap_simple_bind_s(ld, dn, password);
if (ret){
fprintf(stderr, "%s: unable to Bind as user to ldap server: %s\n",
prog, ldap_err2string(ret));
return 1;
}
ldap_memfree(dn);
ldap_unbind(ld);
free(password);
if (setgroups(1, &groupId) != 0) {
fprintf(stderr, "%s: unable to set supplementary groups: %s\n",
prog, strerror(errno));
return 111;
}
if (setgid(groupId) != 0) {
fprintf(stderr, "%s: unable to set gid : %s\n",
prog, strerror(errno));
return 111;
}
if (setuid(userId) != 0) {
fprintf(stderr, "%s: unable to set uid : %s\n",
prog, strerror(errno));
return 111;
}
if (chdir(homeparam) != 0) {
fprintf(stderr, "%s: unable to change to home dir (%s): %s\n",
prog, homeparam, strerror(errno));
return 111;
}
execvp(argv[1], argv + 1);
fprintf(stderr, "%s: unable to exec %s: %s\n", prog, argv[1],
strerror(errno));
return 111;
}