diff options
-rw-r--r-- | src/bin/system/e_system_storage.c | 206 |
1 files changed, 131 insertions, 75 deletions
diff --git a/src/bin/system/e_system_storage.c b/src/bin/system/e_system_storage.c index c243d276e5..c696f0e8c1 100644 --- a/src/bin/system/e_system_storage.c +++ b/src/bin/system/e_system_storage.c @@ -57,7 +57,7 @@ _store_uuid_verify(const char *dev) } static Eina_Bool -_mkdir(const char *path, uid_t u, gid_t g) +_mkdir(const char *path) { mode_t um; int ret, e; @@ -85,112 +85,168 @@ _mkdir(const char *path, uid_t u, gid_t g) ERR("Path is not a dir [%s]\n", path); return EINA_FALSE; } + if (st.st_uid != 0) return EINA_FALSE; + if (st.st_gid != 0) return EINA_FALSE; } + else return EINA_FALSE; } } - if (chown(path, u, g) != 0) + return EINA_TRUE; +} + +static Eina_Bool +_store_is_triplet(const char *mnt, char *dirs[3]) +{ // check that mnt is "/media/xxx/yyy" and nothing more or less. No special + // chars or escapes like \ or * oro ; or { or [ etc. + // no ../ or ./ or empty path elements. then break up the 3 elements + // into dirs[] is we return true + const char *s, *s2; + + dirs[0] = NULL; + dirs[1] = NULL; + dirs[2] = NULL; + + // phase one sanity check + if (!mnt) goto err; + if (mnt[0] != '/') goto err; + for (s = mnt; *s; s++) { - ERR("Can't own [%s] to uid.gid %i.%i\n", path, u, g); - return EINA_FALSE; + if ((*s == '\\') || + (*s == '(') || (*s == '$') || (*s <= '*') || (*s == '`') || + (*s == ';') || (*s == '<') || (*s == '>') || (*s == '?') || + (*s >= '{') || + ((*s >= '[') && (*s <= '^'))) + goto err; } + if ((strstr(mnt, "/..")) || (strstr(mnt, "/./")) || (strstr(mnt, "//"))) + goto err; + + // phase 2 - break up into 3 dir components + s = mnt + 1; + if (*s == '\0') goto err; + s2 = strchr(s, '/'); + if (!s2) goto err; + dirs[0] = malloc(s2 - s + 1); + if (!dirs[0]) goto err; + memcpy(dirs[0], s, s2 - s); + dirs[0][s2 - s] = 0; + s = s2 + 1; + + if (*s == '\0') goto err; + s2 = strchr(s, '/'); + if (!s2) goto err; + dirs[1] = malloc(s2 - s + 1); + if (!dirs[1]) goto err; + memcpy(dirs[1], s, s2 - s); + dirs[1][s2 - s] = 0; + s = s2 + 1; + + if (*s == '\0') goto err; + s2 = strchr(s, '/'); + if (s2) goto err; // different - if there is another / - even trailing + for (s2 = s; *s2 != '\0'; s2++); // s2 - walk to nul byte end + dirs[1] = malloc(s2 - s + 1); + if (!dirs[1]) goto err; + memcpy(dirs[1], s, s2 - s); + dirs[1][s2 - s] = 0; + s = s2 + 1; + return EINA_TRUE; +err: + free(dirs[0]); + free(dirs[1]); + free(dirs[2]); + dirs[0] = NULL; + dirs[1] = NULL; + dirs[2] = NULL; + return EINA_FALSE; } static Eina_Bool _store_mount_verify(const char *mnt) { - char *tmnt, *p, *pp; - const char *s; - struct stat st; + char *dirs[3] = { NULL, NULL, NULL }; + char *tmp = NULL; // XXX: we should use /run/media - possibly make this adapt - if (!(!strncmp(mnt, "/media/", 7))) return EINA_FALSE; - for (s = mnt; *s; s++) - { - if (*s == '\\') return EINA_FALSE; - if ((*s <= '*') || (*s == '`') || (*s == ';') || (*s == '<') || - (*s == '>') || (*s == '?') || (*s >= '{') || - ((*s >= '[') && (*s <= '^'))) - return EINA_FALSE; - } - if (strstr(mnt, "/..")) return EINA_FALSE; - if (strstr(mnt, "/./")) return EINA_FALSE; - if (strstr(mnt, "//")) return EINA_FALSE; - if (stat(mnt, &st) == 0) + if (!mnt) return EINA_FALSE; + if (!(!strncmp(mnt, "/media/", 7))) goto err; + if (!_store_is_triplet(mnt, dirs)) goto err; + tmp = malloc(strlen(mnt) + 1); + if (!tmp) { - if (!S_ISDIR(st.st_mode)) return EINA_FALSE; - if (st.st_uid != 0) return EINA_FALSE; - if (st.st_gid != 0) return EINA_FALSE; - } - tmnt = strdup(mnt); - if (tmnt) - { - // /media <- owned by root - p = strchr(tmnt + 1, '/'); - if (!p) goto malformed; - *p = '\0'; - if (!_mkdir(tmnt, 0, 0)) goto err; - *p = '/'; - - // /media/username <- owned by root - p = strchr(p + 1, '/'); - if (!p) goto malformed; - *p = '\0'; - pp = strrchr(tmnt, '/'); - if (!pp) goto err; - // check if dir name is name of user... - if (strcmp(p + 1, user_name)) goto err; - if (!_mkdir(tmnt, 0, 0)) goto err; - *p = '/'; - - // /media/username/dirname <- owned by root - if (!_mkdir(tmnt, 0, 0)) goto err; - free(tmnt); + free(dirs[0]); + free(dirs[1]); + free(dirs[2]); + return EINA_FALSE; } + // 2nd path must be username + if (!!strcmp(dirs[1], user_name)) goto err; + + tmp[0] = 0; + strcat(tmp, "/"); + strcat(tmp, dirs[0]); + if (!_mkdir(tmp)) goto err; + + strcat(tmp, "/"); + strcat(tmp, dirs[1]); + if (!_mkdir(tmp)) goto err; + + strcat(tmp, "/"); + strcat(tmp, dirs[2]); + if (!_mkdir(tmp)) goto err; + + free(tmp); + free(dirs[0]); + free(dirs[1]); + free(dirs[2]); return EINA_TRUE; -malformed: - ERR("Malformed mount point [%s]\n", mnt); err: - free(tmnt); + ERR("Malformed mount point or create error [%s]\n", mnt); + free(tmp); + free(dirs[0]); + free(dirs[1]); + free(dirs[2]); return EINA_FALSE; } static Eina_Bool _store_umount_verify(const char *mnt) { - char *tmnt, *p; - const char *s; + char *dirs[3] = { NULL, NULL, NULL }; + char *tmp = NULL; struct stat st; // XXX: we should use /run/media - possibly make this adapt - if (!(!strncmp(mnt, "/media/", 7))) return EINA_FALSE; - for (s = mnt; *s; s++) + if (!mnt) return EINA_FALSE; + if (!(!strncmp(mnt, "/media/", 7))) goto err; + if (!_store_is_triplet(mnt, dirs)) goto err; + tmp = malloc(strlen(mnt) + 1); + if (!tmp) { - if (*s == '\\') return EINA_FALSE; - if ((*s <= '*') || (*s == '`') || (*s == ';') || (*s == '<') || - (*s == '>') || (*s == '?') || (*s >= '{') || - ((*s >= '[') && (*s <= '^'))) - return EINA_FALSE; + free(dirs[0]); + free(dirs[1]); + free(dirs[2]); + return EINA_FALSE; } - if (strstr(mnt, "/..")) return EINA_FALSE; - if (strstr(mnt, "/./")) return EINA_FALSE; - if (strstr(mnt, "//")) return EINA_FALSE; - if (stat(mnt, &st) != 0) return EINA_FALSE; - if (!S_ISDIR(st.st_mode)) return EINA_FALSE; - tmnt = strdup(mnt); - if (!tmnt) return EINA_FALSE; - p = strchr(tmnt + 7, '/'); - if (!p) goto err; - *p = '\0'; - if (stat(tmnt, &st) != 0) goto err; + // 2nd path must be username + if (!!strcmp(dirs[1], user_name)) goto err; + if (stat(mnt, &st) != 0) goto err; + if (!S_ISDIR(st.st_mode)) goto err; if (st.st_uid != 0) goto err; if (st.st_gid != 0) goto err; - p = tmnt + 7; // after /media/ (so username) - if (strcmp(p + 1, user_name)) goto err; // not user named dir - free(tmnt); + + free(tmp); + free(dirs[0]); + free(dirs[1]); + free(dirs[2]); return EINA_TRUE; err: - free(tmnt); + ERR("Malformed umount point [%s]\n", mnt); + free(tmp); + free(dirs[0]); + free(dirs[1]); + free(dirs[2]); return EINA_FALSE; } |