On Thu, 2005-01-27 at 09:12 +0100, Peter Stuge wrote:

> But you shouldn't free(tmp) after putenv():ing SHELL, since that will
> free the memory that is actually used in the environment, allowing
> someone else to write there later on, possibly introducing another
> security hole. (Getting repetitive, yes, I know.)
that seems the hardest part to learn, when to free memory and when not.
are there any basic rules/guidelines for that?.

> A side note, the construct (*user).pw_name can (should) be written as
> user->pw_name, which is a lot easier at least on my eyes. :)
> 
I hadn't passed that chapter in the book yet, next chapter now is "Input
and Output". In my opinion the most annoying part of programming.

> > > Something else I encountered:
> > > I use getpwuid() to retrieve the username. But if there is no user
> > > in /etc/passwd for that UID then the function generates a
> > > segmentation fault. Is there a way to catch this? 
> > 
> > Are you sure the function generates the segmentation fault?

At the time i was because it only happend for the user that was not
in /etc/passwd. But it turned out to be an improper call to free()


> Your code looks good, but I may be overlooking something.
Thanks, c turned out be quite easy to learn, atleast the grammer.

this should be the latest update

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 ""

#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;
uid_t userId;
gid_t  groupId;

int main (int argc, char *argv[])
{

	FILE *protocol;
	int uplen, i;

	prog = argv[0];

	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);
	
	//we dont need it anymore. 
	fclose(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)
		fprintf(stderr, "%s: Read username and password: %s/%s \n",
					prog, 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;
	}
		
	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;
	}

	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 from ldap: \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]) {
		fprintf(stderr, "%s: User entry does not contain Emaildirectory: \n", prog);
		return 111;
    }
	homeparam = malloc(strlen(MAILDIR_PREFIX) + strlen(values[0]) + strlen(MAILDIR_POSTFIX) + 1);
	strcpy(homeparam,MAILDIR_PREFIX); 
	strcat(homeparam,values[0]);
	strcat(homeparam,MAILDIR_POSTFIX);



	//use this pointer to check for errors in strtol
	char **endptr = NULL;

	values = ldap_get_values(ld, entry, LDAP_UID_FIELD);
    if (!values || !values[0]) {
		fprintf(stderr, "%s: User entry does not contain user id: \n", prog);
		return 111;
    }
	userId = (uid_t) strtol(values[0], endptr, 10);
	if (endptr != NULL) { 
		//if values[0] is  not  `\0'  but  **endptr  is  `\0'  on return, 
		//the entire string is valid.
		fprintf(stderr, "%s: User entry did not return a numeric user id: \n", prog);
		return 111;
	}
		
	endptr = NULL; //reset endptr
	//userId = atoi(values[0]);


	values = ldap_get_values(ld, entry, LDAP_GID_FIELD);
    if (!values || !values[0]) {
		fprintf(stderr, "%s: User entry does not contain group id: \n", prog);
		return 111;
    }

    groupId = (uid_t) strtol(values[0],  NULL, 10);
	if (endptr != NULL) { 
		//if values[0] is  not  `\0'  but  **endptr  is  `\0'  on return, 
		//the entire string is valid.
		fprintf(stderr, "%s: User entry did not return a numeric user id: \n", prog);
		return 111;
	}
	//groupId = atoi(values[0]);

	//free search result and rebind as user to verify password
	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);




	char *tmp_env;
	struct passwd *user;
	user = getpwuid(userId);
	if(user == NULL){
		fprintf(stderr, "%s: userid does not exist in /etc/passwd: %s \n",
				prog, strerror(errno));
		return 111; //THere is an error.
	}

	tmp_env = malloc(strlen("USER") + strlen((*user).pw_name) + 2);
	strcpy(tmp_env,"USER"); 
	strcat(tmp_env,"=");
	strcat(tmp_env,user->pw_name);
	if(putenv(tmp_env) == -1) {
		fprintf(stderr, "%s: Cannot set environment variable \n",
				prog);
		return 111;
	}

	tmp_env = malloc(strlen("HOME") + strlen((*user).pw_dir) + 2);
	strcpy(tmp_env,"HOME"); 
	strcat(tmp_env,"=");
	strcat(tmp_env, user->pw_dir);
	if(putenv(tmp_env) == -1) {
		fprintf(stderr, "%s: Cannot set environment variable \n",
				prog);
		return 111;
	}
	
	tmp_env = malloc(strlen("SHELL") + strlen((*user).pw_shell) + 2);
	strcpy(tmp_env,"SHELL"); 
	strcat(tmp_env,"=");
	strcat(tmp_env, user->pw_shell);
	if(putenv(tmp_env) == -1) {
		fprintf(stderr, "%s: Cannot set environment variable \n",
				prog);
		return 111;
	}

	
	//For my implementation there are no supplementary groups
	//so we only set out own group as supplementary groups
	if (setgroups(1, &groupId) != 0) {
		fprintf(stderr, "%s: unable to set supplementary groups: %s\n",
				prog, strerror(errno));
		return 111;
	}

	//change to proper group id
	if (setregid(groupId, groupId) != 0) {
		fprintf(stderr, "%s: unable to set gid : %s\n",
				prog, strerror(errno));
		return 111;
	}
	
	//change user id
	if (setreuid(userId, userId) != 0) {
		fprintf(stderr, "%s: unable to set uid : %s\n",
				prog, strerror(errno));
		return 111;
	}

	//change to proper directory
	if (chdir(homeparam) != 0) {
		fprintf(stderr, "%s: unable to change to home dir (%s): %s\n",
				prog, homeparam, strerror(errno));
		return 111;
	}

	//run the next program
	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