2 * ConnMan VPN daemon utils
4 * Copyright (C) 2020 Jolla Ltd. All rights reserved.
5 * Copyright (C) 2020 Open Mobile Platform LLC.
6 * Contact: jussi.laakkonen@jolla.com
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
26 #include <sys/types.h>
30 #include <glib/gstdio.h>
32 #include <connman/log.h>
36 static bool is_string_digits(const char *str)
43 for (i = 0; str[i]; i++) {
44 if (!g_ascii_isdigit(str[i]))
51 static uid_t get_str_id(const char *username)
53 if (!username || !*username)
56 return (uid_t)g_ascii_strtoull(username, NULL, 10);
59 struct passwd *vpn_util_get_passwd(const char *username)
64 if (!username || !*username)
67 if (is_string_digits(username)) {
68 uid = get_str_id(username);
71 pwd = getpwnam(username);
77 struct group *vpn_util_get_group(const char *groupname)
82 if (!groupname || !*groupname)
85 if (is_string_digits(groupname)) {
86 gid = get_str_id(groupname);
89 grp = getgrnam(groupname);
96 * These prefixes are used for checking if the requested path for
97 * vpn_util_create_path() is acceptable. Allow only prefixes meant for run-time
98 * or temporary use to limit the access to any system resources.
100 * VPN core and plugins would need to create only temporary dirs for the
101 * run-time use. The requested dirs can be created for a specific user when
102 * running a VPN plugin as a different user and thus, user specific run dir is
103 * allowed and limitation to access any other system dir is restricted.
105 static const char *allowed_prefixes[] = { "/var/run/connman-vpn/",
106 "/var/run/user/", "/tmp/", NULL };
108 static int is_path_allowed(const char *path)
113 if (!path || !*path || !g_path_is_absolute(path))
116 if (g_strrstr(path, "..") || g_strrstr(path, "./"))
119 for (i = 0; allowed_prefixes[i]; i++) {
120 if (g_str_has_prefix(path, allowed_prefixes[i])) {
121 const char *suffix = path +
122 strlen(allowed_prefixes[i]);
125 * Don't allow plain prefixes, an additional dir must
126 * be included after the prexix in the requested path.
128 if (suffix && *suffix != G_DIR_SEPARATOR &&
130 G_DIR_SEPARATOR_S)) {
131 DBG("allowed %s, has suffix %s", path, suffix);
142 int vpn_util_create_path(const char *path, uid_t uid, gid_t grp, int mode)
148 err = is_path_allowed(path);
152 dir_p = g_path_get_dirname(path);
156 err = g_unlink(dir_p);
168 * Cannot get write access to the containing directory, check
169 * if the path exists.
171 if (!g_file_test(dir_p, G_FILE_TEST_EXISTS))
174 /* If the dir does not exist new one cannot be created */
175 if (!g_file_test(dir_p, G_FILE_TEST_IS_DIR))
178 /* Do a chmod as the dir exists */
181 /* Exists as dir, just chmod and change owner */
182 err = g_chmod(dir_p, mode);
184 connman_warn("chmod %s failed, err %d", dir_p, err);
190 /* Any other error that is not handled here */
191 connman_warn("remove %s failed, err %d", dir_p, err);
195 /* Set dir creation mask to correspond to the mode */
196 old_umask = umask(~mode & 0777);
198 DBG("mkdir %s", dir_p);
199 err = g_mkdir_with_parents(dir_p, mode);
204 connman_warn("mkdir %s failed, err %d", dir_p, err);
211 err = chown(dir_p, uid, grp);
214 connman_warn("chown %s failed for %d/%d, err %d",
215 dir_p, uid, grp, err);