+static gboolean is_numeric(const char *str)
+{
+ gint i;
+
+ if(!str || !(*str))
+ return false;
+
+ for(i = 0; str[i] ; i++) {
+ if(!g_ascii_isdigit(str[i]))
+ return false;
+ }
+
+ return true;
+}
+
+static gint get_gid(const char *group_name)
+{
+ gint gid = -1;
+ struct group *grp;
+
+ if(!group_name || !(*group_name))
+ return gid;
+
+ if (is_numeric(group_name)) {
+ gid_t group_id = (gid_t)g_ascii_strtoull(group_name, NULL, 10);
+ grp = getgrgid(group_id);
+ } else {
+ grp = getgrnam(group_name);
+ }
+
+ if (grp)
+ gid = grp->gr_gid;
+
+ return gid;
+}
+
+static gint get_uid(const char *user_name)
+{
+ gint uid = -1;
+ struct passwd *pw;
+
+ if(!user_name || !(*user_name))
+ return uid;
+
+ if (is_numeric(user_name)) {
+ uid_t user_id = (uid_t)g_ascii_strtoull(user_name, NULL, 10);
+ pw = getpwuid(user_id);
+ } else {
+ pw = getpwnam(user_name);
+ }
+
+ if (pw)
+ uid = pw->pw_uid;
+
+ return uid;
+}
+
+static gint get_supplementary_gids(gchar **groups, gid_t **gid_list)
+{
+ gint group_count = 0;
+ gid_t *list = NULL;
+ int i;
+
+ if (groups) {
+ for(i = 0; groups[i]; i++) {
+ group_count++;
+
+ list = (gid_t*)g_try_realloc(list,
+ sizeof(gid_t) * group_count);
+
+ if (!list) {
+ DBG("cannot allocate supplementary group list");
+ break;
+ }
+
+ list[i] = get_gid(groups[i]);
+ }
+ }
+
+ *gid_list = list;
+
+ return group_count;
+}
+
+static void vpn_task_setup(gpointer user_data)
+{
+ struct vpn_plugin_data *data;
+ gint uid;
+ gint gid;
+ gid_t *gid_list = NULL;
+ size_t gid_list_size;
+ const gchar *user;
+ const gchar *group;
+ gchar **suppl_groups;
+
+ data = user_data;
+ user = vpn_settings_get_binary_user(data);
+ group = vpn_settings_get_binary_group(data);
+ suppl_groups = vpn_settings_get_binary_supplementary_groups(data);
+
+ uid = get_uid(user);
+ gid = get_gid(group);
+ gid_list_size = get_supplementary_gids(suppl_groups, &gid_list);
+
+ DBG("vpn_task_setup uid:%d gid:%d supplementary group list size:%zu",
+ uid, gid, gid_list_size);
+
+
+ /* Change group if proper group name was set, requires CAP_SETGID.*/
+ if (gid > 0 && setgid(gid))
+ connman_error("error setting gid %d %s", gid, strerror(errno));
+
+ /* Set the supplementary groups if list exists, requires CAP_SETGID. */
+ if (gid_list_size && gid_list && setgroups(gid_list_size, gid_list))
+ connman_error("error setting gid list %s", strerror(errno));
+
+ /* Change user for the task if set, requires CAP_SETUID */
+ if (uid > 0 && setuid(uid))
+ connman_error("error setting uid %d %s", uid, strerror(errno));
+}
+
+
+static gboolean update_provider_state(gpointer data)
+{
+ struct vpn_provider *provider = data;
+ struct vpn_data *vpn_data;
+ int index;
+
+ DBG("");
+
+ vpn_data = vpn_provider_get_data(provider);
+
+ index = vpn_provider_get_index(provider);
+ DBG("index to watch %d", index);
+ vpn_provider_ref(provider);
+ vpn_data->watch = vpn_rtnl_add_newlink_watch(index,
+ vpn_newlink, provider);
+ connman_inet_ifup(index);
+
+ return FALSE;
+}
+