[scponly] scponly & multiple users with same uid

Peter Haijen peter at haijen.be
Sat Nov 4 17:11:30 EST 2006


Hello list members,

I've been trying to setup a secure file server accessible via the internet,
and configured scponlyc to help me. This works, and I now have multiple
users accessing a private space on my server using scp/rsync. So far, so
good. My next challenge was integrating scponly with my webdav setup.
Because of the fact that all webdav file access happens as the apache user
(I'm using apache with webdav_fs), I would need to give all my users the
same UID as the UID the apache server is running as, so they could freely
copy files to the server while at the same time those files would be
accessible by apache.

And so I did: I added a new user to /etc/passwd with the UID equal to that
of apache. This setup did not work with scponlyc, because the user entry
scponly retrieves from /etc/passwd is the first entry with the UID, which is
in my case an entry for the apache web user itself, and scponly would try to
chroot to my apache home dir and clearly this is not what I wanted.

To fix this, I did the following: in helper.c, in the function
get_uservar(), I first try looking for a passwd entry using a user name,
which I can easily make unique. I get the user name by examining the last
part of the current working directory, which in my case (and probably most
others as well) is the user name. It that returns a good passwd entry
(pw_uid and pw_dir match with getuid() and getcwd())  I use that. If it does
not work out, I revert to the previous solution of getting the passwd entry
by using getuid().

For example, my apache user has UID 33 and home dir /var/www, and my test1
user has UID 33 and home dir /home/test1. getcwd() returns '/home/test1', of
which I assume the login name is the part after the last '/', thus 'test1';
I lookup the passwd entry by username 'test1', verify that the result indeed
has UID 33 and the correct home dir, and return that as the result instead.
scponlyc will then chroot to /home/test1, my user (who logged in as 'test1')
can now scp a file with UID 33 to the chroot jail /home/test1/incoming, and
apache can read from that location without problems.

I can't think of anything wrong with this approach; every user has a unique
user name, every user's home directory ends with that users login name;
every user and the apache server have the same UID; the apache user can
access each user's files, and each user can only access his own files
because he is chroot()ed.

Unfortunately, I'm no security expert so if anyone can think of a reason why
I would not want to implement this I would be glad to hear it.

This is a diff of the changes I did against version 4.6

--- helper.c.orig       2006-01-31 23:04:16.000000000 +0100
+++ helper.c    2006-11-04 22:29:00.000000000 +0100
@@ -439,9 +439,61 @@
  */
 int get_uservar(void)
 {
-       struct passwd *userinfo;
+       char cwd[FILENAME_MAX];

-       if (NULL==(userinfo=getpwuid(getuid())))
+       struct passwd *userinfo = NULL;
+
+       /*
+        * if we can manage to find the passwd entry by username, we can
support
+        * multiple users with the same uid. we will assume that the
username
+        * is the last part of the current working directory, and see what
we
+        * can come up with
+        */
+       if (getcwd(cwd,sizeof(cwd)) != NULL)
+       {
+               char *s, *login = cwd;
+               while (s = strchr(login,'/'))
+               {
+                       login = s + 1;
+               }
+
+               if (NULL==(userinfo=getpwnam(login)) ||
+                       getuid() != userinfo->pw_uid ||
+                       0 != strncmp(cwd,userinfo->pw_dir,FILENAME_MAX))
+               {
+                       if ( userinfo == NULL )
+                       {
+                               syslog (LOG_WARNING, "no knowledge of
username %s [%s]", login, logstamp());
+                               if (debuglevel)
+                               {
+                                       fprintf (stderr, "no knowledge of
uid %d\n", getuid());
+                                       perror ("getpwuid");
+                               }
+                       }
+                       else if ( getuid() != userinfo->pw_uid )
+                       {
+                               syslog (LOG_WARNING, "username %s: uid %d
does not match %d [%s]", login, userinfo->pw_uid, getuid(), logstamp());
+                               if (debuglevel)
+                               {
+                                       fprintf (stderr, "username %s: uid
%d does not match %d [%s]\n", login, userinfo->pw_uid, getuid());
+                                       perror ("getpwuid");
+                               }
+                       }
+                       else /* 0 !=
strncmp(cwd,userinfo->pw_dir,FILENAME_MAX) */
+                       {
+                               syslog (LOG_WARNING, "username %s: dir does
not match\n", login);
+                               if (debuglevel)
+                               {
+                                       fprintf (stderr, "no knowledge of
uid %d\n", getuid());
+                                       perror ("getpwuid");
+                               }
+                       }
+
+                       userinfo = NULL;
+               }
+       }
+
+       if (userinfo == NULL && NULL==(userinfo=getpwuid(getuid())))
        {
                syslog (LOG_WARNING, "no knowledge of uid %d [%s]",
getuid(), logstamp());
                if (debuglevel)

Regards,

Peter
-------------- next part --------------
HTML attachment scrubbed and removed


More information about the scponly mailing list