return true;
}
+bool valid_shell(const char *p) {
+ /* We have the same requirements, so just piggy-back on the home check.
+ *
+ * Let's ignore /etc/shells because this is only applicable to real and not system users. It is also
+ * incompatible with the idea of empty /etc/. */
+ if (!valid_home(p))
+ return false;
+
+ return !endswith(p, "/"); /* one additional restriction: shells may not be dirs */
+}
+
int maybe_setgroups(size_t size, const gid_t *list) {
int r;
bool valid_gecos(const char *d);
char* mangle_gecos(const char *d);
bool valid_home(const char *p);
-
-static inline bool valid_shell(const char *p) {
- /* We have the same requirements, so just piggy-back on the home check.
- *
- * Let's ignore /etc/shells because this is only applicable to real and
- * not system users. It is also incompatible with the idea of empty /etc.
- */
- return valid_home(p);
-}
+bool valid_shell(const char *p);
int maybe_setgroups(size_t size, const gid_t *list);
assert_se(valid_home("/"));
assert_se(valid_home("/home"));
assert_se(valid_home("/home/foo"));
+ assert_se(valid_home("/home/foo/"));
+}
+
+TEST(valid_shell) {
+ assert_se(!valid_shell(NULL));
+ assert_se(!valid_shell(""));
+ assert_se(!valid_shell("."));
+ assert_se(!valid_shell("/shell/.."));
+ assert_se(!valid_shell("/shell/../"));
+ assert_se(!valid_shell("/shell\n/foo"));
+ assert_se(!valid_shell("./piep"));
+ assert_se(!valid_shell("piep"));
+ assert_se(!valid_shell("/shell/user:lennart"));
+ assert_se(!valid_shell("/"));
+ assert_se(!valid_shell("/bin/sh/"));
+ assert_se(valid_shell("/shell"));
+ assert_se(valid_shell("/shell/foo"));
+ assert_se(valid_shell("/bin/sh"));
}
static void test_get_user_creds_one(const char *id, const char *name, uid_t uid, gid_t gid, const char *home, const char *shell) {