mirror of
https://github.com/systemd/systemd.git
synced 2024-11-27 12:13:33 +08:00
sysusers: move various user credential validity checks to src/basic/
This way we can reuse them for validating User=/Group= settings in unit files (to be added in a later commit). Also, add some tests for them.
This commit is contained in:
parent
bf3dd08a81
commit
e4631b48e1
@ -29,6 +29,7 @@
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <utmp.h>
|
||||
|
||||
#include "missing.h"
|
||||
#include "alloc-util.h"
|
||||
@ -39,6 +40,7 @@
|
||||
#include "path-util.h"
|
||||
#include "string-util.h"
|
||||
#include "user-util.h"
|
||||
#include "utf8.h"
|
||||
|
||||
bool uid_is_valid(uid_t uid) {
|
||||
|
||||
@ -479,3 +481,94 @@ int take_etc_passwd_lock(const char *root) {
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
bool valid_user_group_name(const char *u) {
|
||||
const char *i;
|
||||
long sz;
|
||||
|
||||
/* Checks if the specified name is a valid user/group name. */
|
||||
|
||||
if (isempty(u))
|
||||
return false;
|
||||
|
||||
if (!(u[0] >= 'a' && u[0] <= 'z') &&
|
||||
!(u[0] >= 'A' && u[0] <= 'Z') &&
|
||||
u[0] != '_')
|
||||
return false;
|
||||
|
||||
for (i = u+1; *i; i++) {
|
||||
if (!(*i >= 'a' && *i <= 'z') &&
|
||||
!(*i >= 'A' && *i <= 'Z') &&
|
||||
!(*i >= '0' && *i <= '9') &&
|
||||
*i != '_' &&
|
||||
*i != '-')
|
||||
return false;
|
||||
}
|
||||
|
||||
sz = sysconf(_SC_LOGIN_NAME_MAX);
|
||||
assert_se(sz > 0);
|
||||
|
||||
if ((size_t) (i-u) > (size_t) sz)
|
||||
return false;
|
||||
|
||||
if ((size_t) (i-u) > UT_NAMESIZE - 1)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool valid_user_group_name_or_id(const char *u) {
|
||||
|
||||
/* Similar as above, but is also fine with numeric UID/GID specifications, as long as they are in the right
|
||||
* range, and not the invalid user ids. */
|
||||
|
||||
if (isempty(u))
|
||||
return false;
|
||||
|
||||
if (valid_user_group_name(u))
|
||||
return true;
|
||||
|
||||
return parse_uid(u, NULL) >= 0;
|
||||
}
|
||||
|
||||
bool valid_gecos(const char *d) {
|
||||
|
||||
if (!d)
|
||||
return false;
|
||||
|
||||
if (!utf8_is_valid(d))
|
||||
return false;
|
||||
|
||||
if (string_has_cc(d, NULL))
|
||||
return false;
|
||||
|
||||
/* Colons are used as field separators, and hence not OK */
|
||||
if (strchr(d, ':'))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool valid_home(const char *p) {
|
||||
|
||||
if (isempty(p))
|
||||
return false;
|
||||
|
||||
if (!utf8_is_valid(p))
|
||||
return false;
|
||||
|
||||
if (string_has_cc(p, NULL))
|
||||
return false;
|
||||
|
||||
if (!path_is_absolute(p))
|
||||
return false;
|
||||
|
||||
if (!path_is_safe(p))
|
||||
return false;
|
||||
|
||||
/* Colons are used as field separators, and hence not OK */
|
||||
if (strchr(p, ':'))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -68,3 +68,8 @@ int take_etc_passwd_lock(const char *root);
|
||||
static inline bool userns_supported(void) {
|
||||
return access("/proc/self/uid_map", F_OK) >= 0;
|
||||
}
|
||||
|
||||
bool valid_user_group_name(const char *u);
|
||||
bool valid_user_group_name_or_id(const char *u);
|
||||
bool valid_gecos(const char *d);
|
||||
bool valid_home(const char *p);
|
||||
|
@ -1299,81 +1299,6 @@ static bool item_equal(Item *a, Item *b) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool valid_user_group_name(const char *u) {
|
||||
const char *i;
|
||||
long sz;
|
||||
|
||||
if (isempty(u))
|
||||
return false;
|
||||
|
||||
if (!(u[0] >= 'a' && u[0] <= 'z') &&
|
||||
!(u[0] >= 'A' && u[0] <= 'Z') &&
|
||||
u[0] != '_')
|
||||
return false;
|
||||
|
||||
for (i = u+1; *i; i++) {
|
||||
if (!(*i >= 'a' && *i <= 'z') &&
|
||||
!(*i >= 'A' && *i <= 'Z') &&
|
||||
!(*i >= '0' && *i <= '9') &&
|
||||
*i != '_' &&
|
||||
*i != '-')
|
||||
return false;
|
||||
}
|
||||
|
||||
sz = sysconf(_SC_LOGIN_NAME_MAX);
|
||||
assert_se(sz > 0);
|
||||
|
||||
if ((size_t) (i-u) > (size_t) sz)
|
||||
return false;
|
||||
|
||||
if ((size_t) (i-u) > UT_NAMESIZE - 1)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool valid_gecos(const char *d) {
|
||||
|
||||
if (!d)
|
||||
return false;
|
||||
|
||||
if (!utf8_is_valid(d))
|
||||
return false;
|
||||
|
||||
if (string_has_cc(d, NULL))
|
||||
return false;
|
||||
|
||||
/* Colons are used as field separators, and hence not OK */
|
||||
if (strchr(d, ':'))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool valid_home(const char *p) {
|
||||
|
||||
if (isempty(p))
|
||||
return false;
|
||||
|
||||
if (!utf8_is_valid(p))
|
||||
return false;
|
||||
|
||||
if (string_has_cc(p, NULL))
|
||||
return false;
|
||||
|
||||
if (!path_is_absolute(p))
|
||||
return false;
|
||||
|
||||
if (!path_is_safe(p))
|
||||
return false;
|
||||
|
||||
/* Colons are used as field separators, and hence not OK */
|
||||
if (strchr(p, ':'))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int parse_line(const char *fname, unsigned line, const char *buffer) {
|
||||
|
||||
static const Specifier specifier_table[] = {
|
||||
|
@ -61,6 +61,88 @@ static void test_uid_ptr(void) {
|
||||
assert_se(PTR_TO_UID(UID_TO_PTR(1000)) == 1000);
|
||||
}
|
||||
|
||||
static void test_valid_user_group_name(void) {
|
||||
assert_se(!valid_user_group_name(NULL));
|
||||
assert_se(!valid_user_group_name(""));
|
||||
assert_se(!valid_user_group_name("1"));
|
||||
assert_se(!valid_user_group_name("65535"));
|
||||
assert_se(!valid_user_group_name("-1"));
|
||||
assert_se(!valid_user_group_name("-kkk"));
|
||||
assert_se(!valid_user_group_name("rööt"));
|
||||
assert_se(!valid_user_group_name("."));
|
||||
assert_se(!valid_user_group_name("eff.eff"));
|
||||
assert_se(!valid_user_group_name("foo\nbar"));
|
||||
assert_se(!valid_user_group_name("0123456789012345678901234567890123456789"));
|
||||
assert_se(!valid_user_group_name_or_id("aaa:bbb"));
|
||||
|
||||
assert_se(valid_user_group_name("root"));
|
||||
assert_se(valid_user_group_name("lennart"));
|
||||
assert_se(valid_user_group_name("LENNART"));
|
||||
assert_se(valid_user_group_name("_kkk"));
|
||||
assert_se(valid_user_group_name("kkk-"));
|
||||
assert_se(valid_user_group_name("kk-k"));
|
||||
|
||||
assert_se(valid_user_group_name("some5"));
|
||||
assert_se(!valid_user_group_name("5some"));
|
||||
assert_se(valid_user_group_name("INNER5NUMBER"));
|
||||
}
|
||||
|
||||
static void test_valid_user_group_name_or_id(void) {
|
||||
assert_se(!valid_user_group_name_or_id(NULL));
|
||||
assert_se(!valid_user_group_name_or_id(""));
|
||||
assert_se(valid_user_group_name_or_id("0"));
|
||||
assert_se(valid_user_group_name_or_id("1"));
|
||||
assert_se(valid_user_group_name_or_id("65534"));
|
||||
assert_se(!valid_user_group_name_or_id("65535"));
|
||||
assert_se(valid_user_group_name_or_id("65536"));
|
||||
assert_se(!valid_user_group_name_or_id("-1"));
|
||||
assert_se(!valid_user_group_name_or_id("-kkk"));
|
||||
assert_se(!valid_user_group_name_or_id("rööt"));
|
||||
assert_se(!valid_user_group_name_or_id("."));
|
||||
assert_se(!valid_user_group_name_or_id("eff.eff"));
|
||||
assert_se(!valid_user_group_name_or_id("foo\nbar"));
|
||||
assert_se(!valid_user_group_name_or_id("0123456789012345678901234567890123456789"));
|
||||
assert_se(!valid_user_group_name_or_id("aaa:bbb"));
|
||||
|
||||
assert_se(valid_user_group_name_or_id("root"));
|
||||
assert_se(valid_user_group_name_or_id("lennart"));
|
||||
assert_se(valid_user_group_name_or_id("LENNART"));
|
||||
assert_se(valid_user_group_name_or_id("_kkk"));
|
||||
assert_se(valid_user_group_name_or_id("kkk-"));
|
||||
assert_se(valid_user_group_name_or_id("kk-k"));
|
||||
|
||||
assert_se(valid_user_group_name_or_id("some5"));
|
||||
assert_se(!valid_user_group_name_or_id("5some"));
|
||||
assert_se(valid_user_group_name_or_id("INNER5NUMBER"));
|
||||
}
|
||||
|
||||
static void test_valid_gecos(void) {
|
||||
|
||||
assert_se(!valid_gecos(NULL));
|
||||
assert_se(valid_gecos(""));
|
||||
assert_se(valid_gecos("test"));
|
||||
assert_se(valid_gecos("Ümläüt"));
|
||||
assert_se(!valid_gecos("In\nvalid"));
|
||||
assert_se(!valid_gecos("In:valid"));
|
||||
}
|
||||
|
||||
static void test_valid_home(void) {
|
||||
|
||||
assert_se(!valid_home(NULL));
|
||||
assert_se(!valid_home(""));
|
||||
assert_se(!valid_home("."));
|
||||
assert_se(!valid_home("/home/.."));
|
||||
assert_se(!valid_home("/home/../"));
|
||||
assert_se(!valid_home("/home\n/foo"));
|
||||
assert_se(!valid_home("./piep"));
|
||||
assert_se(!valid_home("piep"));
|
||||
assert_se(!valid_home("/home/user:lennart"));
|
||||
|
||||
assert_se(valid_home("/"));
|
||||
assert_se(valid_home("/home"));
|
||||
assert_se(valid_home("/home/foo"));
|
||||
}
|
||||
|
||||
int main(int argc, char*argv[]) {
|
||||
|
||||
test_uid_to_name_one(0, "root");
|
||||
@ -75,5 +157,10 @@ int main(int argc, char*argv[]) {
|
||||
test_parse_uid();
|
||||
test_uid_ptr();
|
||||
|
||||
test_valid_user_group_name();
|
||||
test_valid_user_group_name_or_id();
|
||||
test_valid_gecos();
|
||||
test_valid_home();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user