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;	
	
}

Reply via email to