Hello,
I was trying to build a chrooted sftp account when I faced a problem. The
chroot is done with the patch present in the contrib subdirectory in the
portable version (I'm under linux slackware current).
My problem is that verifying access rights on directories and files are too
tight and then I couldn't have the following things :
The user sftp, with primary group sftp, is chrooted in /home/sftp/ and his
home is / (in the chroot).
drwxrwxr-t 8 root sftp 4096 Apr 22 03:13 /home/sftp/./
drwxr-x--- 3 root sftp 4096 Apr 22 03:07 /home/sftp/.//.ssh/
-rw-r----- 1 root sftp 641 Apr 22 03:12
/home/sftp/.//.ssh/authorized_keys2
-rw-r----- 1 root sftp 668 Apr 21 23:42 /home/sftp/.//.ssh/id_dsa
-rw-r----- 1 root sftp 600 Apr 21 23:42
/home/sftp/.//.ssh/id_dsa.pub
This is necessary because I don't want him to modify directories such as
.ssh , bin , lib , ... in his chroot whereas he is able to create all that
he wants in his home.
So here is a patch to permit :
. file readable by group if owned by root
. directories writeable by group if owned by root
I added two functions temporarily_use_gid and restore_gid to permit to
access the authorized_keys2 file. The gid used is the primary group of the
user.
This patch fixes only the cases I met.
Here is an up to date chroot patch for 2.5.2p2 too.
And the most important : thanks to all developers of such a great tools.
Regards,
Denis Ducamp.
--
Denis.Ducamp at hsc.fr --- Herv? Schauer Consultants --- http://www.hsc.fr/
snort, hping & dsniff en fran?ais : http://www.groar.org/~ducamp/#sec-trad
Du bon usage de ... http://usenet-fr.news.eu.org/fr-chartes/rfc1855.html
Netiquette Guidelines .... http://www.pasteur.fr/infosci/RFC/18xx/1855
-------------- next part --------------
diff -ur openssh-2.5.2p2.orig/auth-rhosts.c openssh-2.5.2p2/auth-rhosts.c
--- openssh-2.5.2p2.orig/auth-rhosts.c Fri Feb 9 03:11:24 2001
+++ openssh-2.5.2p2/auth-rhosts.c Sun Apr 22 01:19:56 2001
@@ -215,7 +215,8 @@
}
if (options.strict_modes &&
((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
- (st.st_mode & 022) != 0)) {
+ (st.st_uid == 0 && (st.st_mode & 002) != 0) ||
+ (st.st_uid != 0 && (st.st_mode & 022) != 0))) {
log("Rhosts authentication refused for %.100s: bad ownership or modes
for home directory.",
pw->pw_name);
packet_send_debug("Rhosts authentication refused for %.100s: bad
ownership or modes for home directory.",
diff -ur openssh-2.5.2p2.orig/auth-rsa.c openssh-2.5.2p2/auth-rsa.c
--- openssh-2.5.2p2.orig/auth-rsa.c Mon Mar 5 07:47:00 2001
+++ openssh-2.5.2p2/auth-rsa.c Sun Apr 22 01:14:18 2001
@@ -162,7 +162,8 @@
/* Check open file in order to avoid open/stat races */
if (fstat(fileno(f), &st) < 0 ||
(st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
- (st.st_mode & 022) != 0) {
+ (st.st_uid == 0 && (st.st_mode & 002) != 0) ||
+ (st.st_uid != 0 && (st.st_mode & 022) != 0)) {
snprintf(buf, sizeof buf, "RSA authentication refused for %.100s:
"
"bad ownership or modes for '%s'.", pw->pw_name,
file);
fail = 1;
@@ -176,7 +177,8 @@
snprintf(line, sizeof line, "%.500s/%.100s", pw->pw_dir,
check[i]);
if (stat(line, &st) < 0 ||
(st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
- (st.st_mode & 022) != 0) {
+ (st.st_uid == 0 && (st.st_mode & 002) != 0) ||
+ (st.st_uid != 0 && (st.st_mode & 022) != 0)) {
snprintf(buf, sizeof buf, "RSA authentication refused for %.100s:
"
"bad ownership or modes for '%s'.", pw->pw_name,
line);
fail = 1;
diff -ur openssh-2.5.2p2.orig/auth2.c openssh-2.5.2p2/auth2.c
--- openssh-2.5.2p2.orig/auth2.c Sun Mar 11 21:01:56 2001
+++ openssh-2.5.2p2/auth2.c Sun Apr 22 01:05:40 2001
@@ -586,6 +586,7 @@
return 0;
/* Temporarily use the user's uid. */
+ temporarily_use_gid(pw->pw_gid);
temporarily_use_uid(pw->pw_uid);
/* The authorized keys. */
@@ -596,6 +597,7 @@
if (stat(file, &st) < 0) {
/* Restore the privileged uid. */
restore_uid();
+ restore_gid();
return 0;
}
/* Open the file containing the authorized keys. */
@@ -603,6 +605,7 @@
if (!f) {
/* Restore the privileged uid. */
restore_uid();
+ restore_gid();
return 0;
}
if (options.strict_modes) {
@@ -611,7 +614,8 @@
/* Check open file in order to avoid open/stat races */
if (fstat(fileno(f), &st) < 0 ||
(st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
- (st.st_mode & 022) != 0) {
+ (st.st_uid == 0 && (st.st_mode & 002) != 0) ||
+ (st.st_uid != 0 && (st.st_mode & 022) != 0)) {
snprintf(buf, sizeof buf,
"%s authentication refused for %.100s: "
"bad ownership or modes for '%s'.",
@@ -628,7 +632,8 @@
pw->pw_dir, check[i]);
if (stat(line, &st) < 0 ||
(st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
- (st.st_mode & 022) != 0) {
+ (st.st_uid == 0 && (st.st_mode & 002) != 0) ||
+ (st.st_uid != 0 && (st.st_mode & 022) != 0)) {
snprintf(buf, sizeof buf,
"%s authentication refused for %.100s: "
"bad ownership or modes for '%s'.",
@@ -642,6 +647,7 @@
fclose(f);
log("%s", buf);
restore_uid();
+ restore_gid();
return 0;
}
}
@@ -686,6 +692,7 @@
}
}
restore_uid();
+ restore_gid();
fclose(f);
key_free(found);
if (!found_key)
diff -ur openssh-2.5.2p2.orig/authfile.c openssh-2.5.2p2/authfile.c
--- openssh-2.5.2p2.orig/authfile.c Mon Mar 5 05:59:27 2001
+++ openssh-2.5.2p2/authfile.c Sun Apr 22 02:04:53 2001
@@ -513,7 +513,8 @@
#endif
if (fstat(fd, &st) < 0 ||
(st.st_uid != 0 && getuid() != 0 && st.st_uid != getuid())
||
- (st.st_mode & 077) != 0) {
+ (st.st_uid == 0 && (st.st_mode & 037) != 0) ||
+ (st.st_uid != 0 && (st.st_mode & 077) != 0)) {
close(fd);
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("@ WARNING: UNPROTECTED PRIVATE KEY FILE!
@");
diff -ur openssh-2.5.2p2.orig/uidswap.c openssh-2.5.2p2/uidswap.c
--- openssh-2.5.2p2.orig/uidswap.c Mon Feb 26 22:39:07 2001
+++ openssh-2.5.2p2/uidswap.c Sat Apr 21 23:23:00 2001
@@ -32,6 +32,7 @@
#define SAVED_IDS_WORK_WITH_SETEUID
/* Saved effective uid. */
static uid_t saved_euid = 0;
+static gid_t saved_egid = 0;
#endif
/*
@@ -59,6 +60,27 @@
#endif /* SAVED_IDS_WORK_WITH_SETEUID */
}
+void
+temporarily_use_gid(gid_t gid)
+{
+#ifdef SAVED_IDS_WORK_WITH_SETEUID
+ /* Save the current egid. */
+ saved_egid = getegid();
+
+ /* Set the effective gid to the given (unprivileged) gid. */
+ if (setegid(gid) == -1)
+ debug("setegid %u: %.100s", (u_int) gid, strerror(errno));
+#else /* SAVED_IDS_WORK_WITH_SETEUID */
+ /* Propagate the privileged gid to all of our gids. */
+ if (setgid(getegid()) < 0)
+ debug("setgid %u: %.100s", (u_int) getegid(), strerror(errno));
+
+ /* Set the effective gid to the given (unprivileged) gid. */
+ if (setegid(gid) == -1)
+ debug("setegid %u: %.100s", (u_int) gid, strerror(errno));
+#endif /* SAVED_IDS_WORK_WITH_SETEUID */
+}
+
/*
* Restores to the original uid.
*/
@@ -76,6 +98,23 @@
* as well.
*/
setuid(getuid());
+#endif /* SAVED_IDS_WORK_WITH_SETEUID */
+}
+
+void
+restore_gid(void)
+{
+#ifdef SAVED_IDS_WORK_WITH_SETEUID
+ /* Set the effective gid back to the saved gid. */
+ if (setegid(saved_egid) < 0)
+ debug("setegid %u: %.100s", (u_int) saved_egid, strerror(errno));
+#else /* SAVED_IDS_WORK_WITH_SETEUID */
+ /*
+ * We are unable to restore the real gid to its unprivileged value.
+ * Propagate the real gid (usually more privileged) to effective gid
+ * as well.
+ */
+ setgid(getgid());
#endif /* SAVED_IDS_WORK_WITH_SETEUID */
}
diff -ur openssh-2.5.2p2.orig/uidswap.h openssh-2.5.2p2/uidswap.h
--- openssh-2.5.2p2.orig/uidswap.h Mon Jan 29 08:39:26 2001
+++ openssh-2.5.2p2/uidswap.h Sat Apr 21 23:18:07 2001
@@ -20,12 +20,14 @@
* root, this does nothing. This call cannot be nested.
*/
void temporarily_use_uid(uid_t uid);
+void temporarily_use_gid(uid_t uid);
/*
* Restores the original effective user id after temporarily_use_uid().
* This should only be called while temporarily_use_uid is effective.
*/
void restore_uid(void);
+void restore_gid(void);
/*
* Permanently sets all uids to the given uid. This cannot be called while
-------------- next part --------------
diff -ur openssh-2.5.2p2.orig/session.c openssh-2.5.2p2/session.c
--- openssh-2.5.2p2.orig/session.c Thu Mar 22 01:58:27 2001
+++ openssh-2.5.2p2/session.c Fri Apr 20 15:45:09 2001
@@ -93,6 +93,8 @@
# include <uinfo.h>
#endif
+#define CHROOT
+
/* types */
#define TTYSZ 64
@@ -1012,6 +1014,10 @@
extern char **environ;
struct stat st;
char *argv[10];
+#ifdef CHROOT
+ char *user_dir;
+ char *new_root;
+#endif /* CHROOT */
int do_xauth = s->auth_proto != NULL && s->auth_data != NULL;
#ifdef WITH_IRIX_PROJECT
prid_t projid;
@@ -1085,6 +1091,28 @@
if (setlogin(pw->pw_name) < 0)
error("setlogin failed: %s", strerror(errno));
+
+#ifdef CHROOT
+ user_dir = xstrdup(pw->pw_dir);
+ new_root = user_dir + 1;
+
+
+ while((new_root = strchr(new_root, '.')) != NULL) {
+ new_root--;
+ if(strncmp(new_root, "/./", 3) == 0) {
+ *new_root = '\0';
+ new_root += 2;
+
+ if(chroot(user_dir) != 0)
+ fatal("Couldn't chroot to user
directory %s", user_dir);
+
+ pw->pw_dir = new_root;
+ break;
+ }
+ new_root += 2;
+ }
+#endif /* CHROOT */
+
if (setgid(pw->pw_gid) < 0) {
perror("setgid");
exit(1);