I am trying to make a few fixes and enhancements to Jailkit. The source is in CVS version control so I cloned it to GitHub.
The way this is set up, you edit a user's home directory in /etc/passwd
to be something like:
/home/jail/./home/username
Then the getjaildir
function reads over that which is passed in as oldhomedir
until it finds the first /./
match right to left on the string and then will set jaildir
to what is to the left of that and the newhomedir
to everything to the right of that.
I want to be able to override jaildir
with the value from a configuration file - but I suck at c
and so I am having very difficult time even setting the variables manually.
Here is the function:
/* if it returns 1 it will allocate new memory for jaildir and newhomedir
* else it will return 0
*/
int getjaildir(const char *oldhomedir, char **jaildir, char **newhomedir) {
int i=strlen(oldhomedir);
/* we will not accept /./ as jail, so we continue looking while i > 4 (minimum then is /a/./ )
* we start at the end so if there are multiple /path/./path2/./path3 the user will be jailed in the most minimized path
*/
while (i > 4) {
/* DEBUG_MSG("oldhomedir[%d]=%c\n",i,oldhomedir[i]);*/
if (oldhomedir[i] == '/' && oldhomedir[i-1] == '.' && oldhomedir[i-2] == '/') {
DEBUG_MSG("&oldhomedir[%d]=%s\n",i,&oldhomedir[i]);
*jaildir = strndup(oldhomedir, i-2);
*newhomedir = strdup(&oldhomedir[i]);
return 1;
}
i--;
}
return 1;
}
After many, many attempts at a more complex solution I tried a very simple, hard-coded variation:
int getjaildir(const char *oldhomedir, char **jaildir, char **newhomedir) {
*jaildir = "/home/jail";
*newhomedir = "/home/username";
return 1;
}
This compiles fine on linux but when I run it I end up getting Segmentation fault (11)
. I read up on pointers, addresses, dereferencing, variable types, string concatenation, etc. but unfortunately I'm used to loosely typed languages so this is pretty hard. What am I doing wrong?
update
Instead of setting the values in the getjaildir
function I am attempting to set them in the mail loop.
At the top of the loop we have the variable definitions:
char *jaildir=NULL, *newhome=NULL, *shell=NULL;
And here is where the function to set them is called:
if (!getjaildir(pw->pw_dir, &jaildir, &newhome)) {
syslog(LOG_ERR, "abort, failed to read the jail and the home from %s for user %s (%d)",pw->pw_dir, pw->pw_name, getuid());
exit(17);
}
Can I just do this immediately afterwards to overwrite the values?
jaildir="/home/jail";
newhome="/home/testuser";
When I try this it gives me:
*** glibc detected *** -su: munmap_chunk(): invalid pointer: 0x00000000004046ee ***
How do you call getjaildir
?
When I tried it, it works, as it should.
int getjaildir(const char *oldhomedir, char **jaildir, char **newhomedir)
{
*jaildir = "/home/jail";
*newhomedir = "/home/username";
return 1;
}
int main(int argc, char *argv[])
{
char *ohome = "ohome";
char *nhome = "nhome";
char *jdir = "jdir";
getjaildir(ohome, &jdir, &nhome);
printf("%s:%s:%s\n", ohome, jdir, nhome);
}
Output:
ohome:/home/jail:/home/username
update
I looked at oyur link and now I think I know what the problem is. You are retrieving the password stucture with a call to gepwnam
. However this function returns a static memory, which you should NOT overwerwrite. So either you have to copy the strcuture manually, before you start modifying it, or you provide your own memory to it. For details on how to this you can refer to http://linux.die.net/man/3/getpwnam and look at getpwnam_r
. Basically you allocate this memory beforehand and pass it to the function. You must make sure that enough memory is allocated as all the entries are put into this buffer you provided.
When you change your code accordingly it shouldn't crash.