default to erroring if we can't remap a uid/gid
authorMike Kelly <mike@pair.com>
Tue, 20 Dec 2011 15:27:51 +0000 (10:27 -0500)
committerMiklos Szeredi <mszeredi@suse.cz>
Wed, 21 Dec 2011 09:05:08 +0000 (10:05 +0100)
add a '-o nomap=ignore|error' option, which defaults to 'error'

sshfs.1
sshfs.c

diff --git a/sshfs.1 b/sshfs.1
index 9dcd8aa..27dd8bc 100644 (file)
--- a/sshfs.1
+++ b/sshfs.1
@@ -116,6 +116,17 @@ file containing username:uid mappings for \fBidmap=file\fR
 file containing groupname:gid mappings for \fBidmap=file\fR
 .RE
 .TP
+\fB\-o\fR nomap=TYPE
+with idmap=file, how to handle missing mappings
+.RS 8
+.TP
+ignore
+don't do any re-mapping
+.TP
+error
+return an error (default)
+.RE
+.TP
 \fB\-o\fR ssh_command=CMD
 execute CMD instead of 'ssh'
 .TP
diff --git a/sshfs.c b/sshfs.c
index bf7e956..749e134 100644 (file)
--- a/sshfs.c
+++ b/sshfs.c
@@ -201,6 +201,7 @@ struct sshfs {
        int no_check_root;
        int detect_uid;
        int idmap;
+       int nomap;
        char *uid_file;
        char *gid_file;
        GHashTable *uid_map;
@@ -321,6 +322,11 @@ enum {
        IDMAP_FILE,
 };
 
+enum {
+       NOMAP_IGNORE,
+       NOMAP_ERROR,
+};
+
 #define SSHFS_OPT(t, p, v) { t, offsetof(struct sshfs, p), v }
 
 static struct fuse_opt sshfs_opts[] = {
@@ -337,6 +343,8 @@ static struct fuse_opt sshfs_opts[] = {
        SSHFS_OPT("idmap=file",        idmap, IDMAP_FILE),
        SSHFS_OPT("uidfile=%s",        uid_file, 0),
        SSHFS_OPT("gidfile=%s",        gid_file, 0),
+       SSHFS_OPT("nomap=ignore",      nomap, NOMAP_IGNORE),
+       SSHFS_OPT("nomap=error",       nomap, NOMAP_ERROR),
        SSHFS_OPT("sshfs_sync",        sync_write, 1),
        SSHFS_OPT("no_readahead",      sync_read, 1),
        SSHFS_OPT("sshfs_debug",       debug, 1),
@@ -464,11 +472,20 @@ static int list_empty(const struct list_head *head)
 
 /* given a pointer to the uid/gid, and the mapping table, remap the
  * uid/gid, if necessary */
-static inline void translate_id(uint32_t *id, GHashTable *map)
+static inline int translate_id(uint32_t *id, GHashTable *map)
 {
        gpointer id_p;
-       if (g_hash_table_lookup_extended(map, GUINT_TO_POINTER(*id), NULL, &id_p))
+       if (g_hash_table_lookup_extended(map, GUINT_TO_POINTER(*id), NULL, &id_p)) {
                *id = GPOINTER_TO_UINT(id_p);
+               return 0;
+       }
+       switch (sshfs.nomap) {
+       case NOMAP_ERROR: return -1;
+       case NOMAP_IGNORE: return 0;
+       default:
+               fprintf(stderr, "internal error\n");
+               abort();
+       }
 }
 
 static inline void buf_init(struct buffer *buf, size_t size)
@@ -672,36 +689,36 @@ static int buf_get_attrs(struct buffer *buf, struct stat *stbuf, int *flagsp)
        uint32_t mode = S_IFREG | 0777;
 
        if (buf_get_uint32(buf, &flags) == -1)
-               return -1;
+               return -EIO;
        if (flagsp)
                *flagsp = flags;
        if ((flags & SSH_FILEXFER_ATTR_SIZE) &&
            buf_get_uint64(buf, &size) == -1)
-               return -1;
+               return -EIO;
        if ((flags & SSH_FILEXFER_ATTR_UIDGID) &&
            (buf_get_uint32(buf, &uid) == -1 ||
             buf_get_uint32(buf, &gid) == -1))
-               return -1;
+               return -EIO;
        if ((flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
            buf_get_uint32(buf, &mode) == -1)
-               return -1;
+               return -EIO;
        if ((flags & SSH_FILEXFER_ATTR_ACMODTIME)) {
                if (buf_get_uint32(buf, &atime) == -1 ||
                    buf_get_uint32(buf, &mtime) == -1)
-                       return -1;
+                       return -EIO;
        }
        if ((flags & SSH_FILEXFER_ATTR_EXTENDED)) {
                uint32_t extcount;
                unsigned i;
                if (buf_get_uint32(buf, &extcount) == -1)
-                       return -1;
+                       return -EIO;
                for (i = 0; i < extcount; i++) {
                        struct buffer tmp;
                        if (buf_get_data(buf, &tmp) == -1)
-                               return -1;
+                               return -EIO;
                        buf_free(&tmp);
                        if (buf_get_data(buf, &tmp) == -1)
-                               return -1;
+                               return -EIO;
                        buf_free(&tmp);
                }
        }
@@ -709,9 +726,11 @@ static int buf_get_attrs(struct buffer *buf, struct stat *stbuf, int *flagsp)
        if (sshfs.remote_uid_detected && uid == sshfs.remote_uid)
                uid = sshfs.local_uid;
        if (sshfs.idmap == IDMAP_FILE && sshfs.uid_map)
-               translate_id(&uid, sshfs.uid_map);
+               if (translate_id(&uid, sshfs.uid_map) == -1)
+                       return -EPERM;
        if (sshfs.idmap == IDMAP_FILE && sshfs.gid_map)
-               translate_id(&gid, sshfs.gid_map);
+               if (translate_id(&gid, sshfs.gid_map) == -1)
+                       return -EPERM;
 
        memset(stbuf, 0, sizeof(struct stat));
        stbuf->st_mode = mode;
@@ -778,7 +797,7 @@ static int buf_get_entries(struct buffer *buf, fuse_cache_dirh_t h,
        unsigned i;
 
        if (buf_get_uint32(buf, &count) == -1)
-               return -1;
+               return -EIO;
 
        for (i = 0; i < count; i++) {
                int err = -1;
@@ -786,16 +805,16 @@ static int buf_get_entries(struct buffer *buf, fuse_cache_dirh_t h,
                char *longname;
                struct stat stbuf;
                if (buf_get_string(buf, &name) == -1)
-                       return -1;
+                       return -EIO;
                if (buf_get_string(buf, &longname) != -1) {
                        free(longname);
-                       if (buf_get_attrs(buf, &stbuf, NULL) != -1) {
+                       err = buf_get_attrs(buf, &stbuf, NULL);
+                       if (!err) {
                                if (sshfs.follow_symlinks &&
                                    S_ISLNK(stbuf.st_mode)) {
                                        stbuf.st_mode = 0;
                                }
                                filler(h, name, &stbuf);
-                               err = 0;
                        }
                }
                free(name);
@@ -1552,7 +1571,7 @@ static void sftp_detect_uid()
                fprintf(stderr, "failed to stat home directory (%i)\n", serr);
                goto out;
        }
-       if (buf_get_attrs(&buf, &stbuf, &flags) == -1)
+       if (buf_get_attrs(&buf, &stbuf, &flags) != 0)
                goto out;
 
        if (!(flags & SSH_FILEXFER_ATTR_UIDGID))
@@ -1610,8 +1629,12 @@ static int sftp_check_root(const char *base_path)
 
                goto out;
        }
-       if (buf_get_attrs(&buf, &stbuf, &flags) == -1)
+
+       int err2 = buf_get_attrs(&buf, &stbuf, &flags);
+       if (err2) {
+               err = err2;
                goto out;
+       }
 
        if (!(flags & SSH_FILEXFER_ATTR_PERMISSIONS))
                goto out;
@@ -1867,8 +1890,7 @@ static int sshfs_getattr(const char *path, struct stat *stbuf)
        err = sftp_request(sshfs.follow_symlinks ? SSH_FXP_STAT : SSH_FXP_LSTAT,
                           &buf, SSH_FXP_ATTRS, &outbuf);
        if (!err) {
-               if (buf_get_attrs(&outbuf, stbuf, NULL) == -1)
-                       err = -EIO;
+               err = buf_get_attrs(&outbuf, stbuf, NULL);
                buf_free(&outbuf);
        }
        buf_free(&buf);
@@ -1990,8 +2012,7 @@ static int sshfs_getdir(const char *path, fuse_cache_dirh_t h,
                        struct buffer name;
                        err = sftp_request(SSH_FXP_READDIR, &handle, SSH_FXP_NAME, &name);
                        if (!err) {
-                               if (buf_get_entries(&name, h, filler) == -1)
-                                       err = -EIO;
+                               err = buf_get_entries(&name, h, filler);
                                buf_free(&name);
                        }
                } while (!err);
@@ -2190,9 +2211,11 @@ static int sshfs_chown(const char *path, uid_t uid, gid_t gid)
        if (sshfs.remote_uid_detected && uid == sshfs.local_uid)
                uid = sshfs.remote_uid;
        if (sshfs.idmap == IDMAP_FILE && sshfs.r_uid_map)
-               translate_id(&uid, sshfs.r_uid_map);
+               if(translate_id(&uid, sshfs.r_uid_map) == -1)
+                       return -EPERM;
        if (sshfs.idmap == IDMAP_FILE && sshfs.r_gid_map)
-               translate_id(&gid, sshfs.r_gid_map);
+               if (translate_id(&gid, sshfs.r_gid_map) == -1)
+                       return -EPERM;
 
        buf_init(&buf, 0);
        buf_add_path(&buf, path);
@@ -2314,8 +2337,7 @@ static int sshfs_open_common(const char *path, mode_t mode,
        type = sshfs.follow_symlinks ? SSH_FXP_STAT : SSH_FXP_LSTAT;
        err2 = sftp_request(type, &buf, SSH_FXP_ATTRS, &outbuf);
        if (!err2) {
-               if (buf_get_attrs(&outbuf, &stbuf, NULL) == -1)
-                       err2 = -EIO;
+               err2 = buf_get_attrs(&outbuf, &stbuf, NULL);
                buf_free(&outbuf);
        }
        err = sftp_request_wait(open_req, SSH_FXP_OPEN, SSH_FXP_HANDLE,
@@ -2927,8 +2949,7 @@ static int sshfs_fgetattr(const char *path, struct stat *stbuf,
        buf_add_buf(&buf, &sf->handle);
        err = sftp_request(SSH_FXP_FSTAT, &buf, SSH_FXP_ATTRS, &outbuf);
        if (!err) {
-               if (buf_get_attrs(&outbuf, stbuf, NULL) == -1)
-                       err = -EIO;
+               err = buf_get_attrs(&outbuf, stbuf, NULL);
                buf_free(&outbuf);
        }
        buf_free(&buf);
@@ -3143,6 +3164,9 @@ static void usage(const char *progname)
 "             file             translate UIDs/GIDs contained in uidfile/gidfile\n"
 "    -o uidfile=FILE        file containing username:remote_uid mappings\n"
 "    -o gidfile=FILE        file containing groupname:remote_gid mappings\n"
+"    -o nomap=TYPE          with idmap=file, how to handle missing mappings\n"
+"             ignore           don't do any re-mapping\n"
+"             error            return an error (default)\n"
 "    -o ssh_command=CMD     execute CMD instead of 'ssh'\n"
 "    -o ssh_protocol=N      ssh protocol to use (default: 2)\n"
 "    -o sftp_server=SERV    path to sftp server or subsystem (default: sftp)\n"
@@ -3452,7 +3476,7 @@ static int ssh_connect(void)
                        return -1;
 
                if (!sshfs.no_check_root &&
-                   sftp_check_root(sshfs.base_path) == -1)
+                   sftp_check_root(sshfs.base_path) != 0)
                        return -1;
 
        }
@@ -3647,6 +3671,7 @@ int main(int argc, char *argv[])
        sshfs.delay_connect = 0;
        sshfs.detect_uid = 0;
        sshfs.idmap = IDMAP_NONE;
+       sshfs.nomap = NOMAP_ERROR;
        ssh_add_arg("ssh");
        ssh_add_arg("-x");
        ssh_add_arg("-a");