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