relaxing access rights verifications

Denis Ducamp Denis.Ducamp at hsc.fr
Sun Apr 22 11:41:08 EST 2001


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


More information about the openssh-unix-dev mailing list