[PATCH] add restricted mode to sftp-server

Pavel Volkov pavelivolkov at gmail.com
Wed Jun 5 04:03:48 EST 2013


Hi again. Attachment is lost in the mailing list. I'm sorry. I will
repeat them again in the body.

--- sftp-server.8.orig    2013-06-04 13:32:44.000000000 +0400
+++ sftp-server.8    2013-06-04 18:08:32.000000000 +0400
@@ -99,6 +99,13 @@
 into a read-only mode.
 Attempts to open files for writing, as well as other operations that change
 the state of the filesystem, will be denied.
+.It Fl r
+Places this instance of
+.Nm
+into a restricted mode.
+Attempts to open files for writing, as well as other operations that change
+the state of the filesystem, will be denied if files already exist.
+Allows to resume via 'put' command for such program as winscp or
filezilla, or other.
 .It Fl u Ar umask
 Sets an explicit
 .Xr umask 2

--- sftp-server.c.orig    2013-01-04 23:26:38.000000000 +0400
+++ sftp-server.c    2013-06-04 12:22:35.000000000 +0400
@@ -64,6 +64,9 @@
 /* Disable writes */
 int readonly;

+/* Disable change if file exist */
+int nochange=0;
+
 /* portable attributes, etc. */

 typedef struct Stat Stat;
@@ -533,6 +536,28 @@
     buffer_free(&msg);
 }

+static int
+fnochange(const char *name)
+{
+    const char *filepart = ".filepart";
+    char bname[PATH_MAX], *pbname;
+    struct stat st;
+
+    if(nochange) { /* nochange = 1 */
+        pbname=stpncpy(bname,name,sizeof(bname)-1);
+        bname[sizeof(bname)-1]='\0';
+        debug3("fnochange 1: bname=%s, length bname=%d", bname, strlen(bname));
+        if(strlen(name)>strlen(filepart)) {
+            pbname-=strlen(filepart);
+            debug3("fnochange 2: pbname=%s, length pbname=%d",
pbname, strlen(pbname));
+            if(bcmp(pbname,filepart,strlen(filepart))==0) *pbname='\0';
+        }
+        debug3("fnochange 3: bname=%s, length bname=%d", bname, strlen(bname));
+        if(lstat(bname,&st)!=-1) return 1;
+    }
+    return 0;
+}
+
 static void
 process_open(void)
 {
@@ -550,7 +575,7 @@
     mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
     logit("open \"%s\" flags %s mode 0%o",
         name, string_from_portable(pflags), mode);
-    if (readonly &&
+    if ((readonly || (fnochange(name) && (flags != O_WRONLY))) &&
         ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR))
         status = SSH2_FX_PERMISSION_DENIED;
     else {
@@ -762,7 +787,7 @@
     name = get_string(NULL);
     a = get_attrib();
     debug("request %u: setstat name \"%s\"", id, name);
-    if (readonly) {
+    if (readonly || fnochange(name)) {
         status = SSH2_FX_PERMISSION_DENIED;
         a->flags = 0;
     }
@@ -954,7 +979,7 @@
     name = get_string(NULL);
     debug3("request %u: remove", id);
     logit("remove name \"%s\"", name);
-    if (readonly)
+    if (readonly || fnochange(name))
         status = SSH2_FX_PERMISSION_DENIED;
     else {
         ret = unlink(name);
@@ -1000,7 +1025,7 @@
     name = get_string(NULL);
     debug3("request %u: rmdir", id);
     logit("rmdir name \"%s\"", name);
-    if (readonly)
+    if (readonly || fnochange(name))
         status = SSH2_FX_PERMISSION_DENIED;
     else {
         ret = rmdir(name);
@@ -1050,7 +1075,7 @@
     debug3("request %u: rename", id);
     logit("rename old \"%s\" new \"%s\"", oldpath, newpath);
     status = SSH2_FX_FAILURE;
-    if (readonly)
+    if (readonly || fnochange(oldpath))
         status = SSH2_FX_PERMISSION_DENIED;
     else if (lstat(oldpath, &sb) == -1)
         status = errno_to_portable(errno);
@@ -1150,7 +1175,7 @@
     newpath = get_string(NULL);
     debug3("request %u: posix-rename", id);
     logit("posix-rename old \"%s\" new \"%s\"", oldpath, newpath);
-    if (readonly)
+    if (readonly || fnochange(oldpath))
         status = SSH2_FX_PERMISSION_DENIED;
     else {
         ret = rename(oldpath, newpath);
@@ -1362,7 +1387,7 @@
     extern char *__progname;

     fprintf(stderr,
-        "usage: %s [-ehR] [-d start_directory] [-f log_facility] "
+        "usage: %s [-ehRr] [-d start_directory] [-f log_facility] "
         "[-l log_level]\n\t[-u umask]\n",
         __progname);
     exit(1);
@@ -1385,8 +1410,11 @@

     pw = pwcopy(user_pw);

-    while (!skipargs && (ch = getopt(argc, argv, "d:f:l:u:cehR")) != -1) {
+    while (!skipargs && (ch = getopt(argc, argv, "d:f:l:u:cehRr")) != -1) {
         switch (ch) {
+        case 'r':
+            nochange = 1;
+            break;
         case 'R':
             readonly = 1;
             break;

On Tue, Jun 4, 2013 at 6:46 PM, Pavel Volkov <pavelivolkov at gmail.com> wrote:
> Hello.
> These patches add a new mode of operation for the sftp server.
> It is located between the ordinary, unrestricted mode and read-only mode.
> It allows you to add files to the server, but only if these files do
> not exist on the server before.
> Changes to existing files - are prohibited.
> Please review them, maybe these patches will be useful not only to me.
> Thank you.


More information about the openssh-unix-dev mailing list