Skip to content
Snippets Groups Projects
Verified Commit 12e73f9f authored by Suvendhu Hansa's avatar Suvendhu Hansa :speech_balloon: Committed by IOPSYS Dev
Browse files

Unified datamodel daemon

parent 99bf586d
No related branches found
No related tags found
1 merge request!35Usermngr daemonization
Pipeline #182450 passed
LIB = libusermngr.so
PROG := usermngr
LIB_OBJS = users.o
OBJS := main.o users.o helper.o
PROG_CFLAGS = $(CFLAGS) -Wall -Werror -fPIC
LIB_LDFLAGS = $(LDFLAGS) -lcrypto
PROG_CFLAGS = $(CFLAGS) -Wall -Werror -fPIC -g
PROG_LDFLAGS = $(LDFLAGS) -lcrypto -luci -lubus -lubox -lblobmsg_json -lbbfdm-ubus -lbbfdm-api
.PHONY: all
%.o: %.c
$(CC) $(PROG_CFLAGS) -c -o $@ $<
all: $(LIB)
all: $(PROG)
$(LIB): $(LIB_OBJS)
$(CC) $(PROG_CFLAGS) -shared -o $@ $^ $(LIB_LDFLAGS)
$(PROG): $(OBJS)
$(CC) $(PROG_CFLAGS) -o $@ $^ $(PROG_LDFLAGS)
clean:
rm -f *.o $(LIB)
rm -f *.o $(PROG)
/*
* helper.c: usermngr helper functions
*
* Copyright (C) 2024 IOPSYS Software Solutions AB. All rights reserved.
*
* Author: Suvendhu Hansa <suvendhu.hansa@iopsys.eu>
*
* See LICENSE file for license related information.
*/
#include <string.h>
#include <ctype.h>
#include <libubox/blobmsg.h>
#include <libubox/blobmsg_json.h>
#include <libubus.h>
#include "users.h"
#include "helper.h"
static struct uci_context *uci_ctx = NULL;
static int usermgr_commit_package(const char *package)
{
struct uci_ptr ptr = {0};
// cppcheck-suppress cert-EXP05-C
if (uci_lookup_ptr(uci_ctx, &ptr, (char *)package, true) != UCI_OK) {
return -1;
}
if (uci_commit(uci_ctx, &ptr.p, false) != UCI_OK) {
return -1;
}
return 0;
}
int usermgr_uci_init(const char *conf_path)
{
uci_ctx = uci_alloc_context();
if (!uci_ctx)
return -1;
uci_set_confdir(uci_ctx, conf_path);
return 0;
}
int usermgr_uci_fini(const char *package_name)
{
/* Commit package */
if (package_name)
usermgr_commit_package(package_name);
/* Freed uci context */
if (uci_ctx) {
uci_free_context(uci_ctx);
uci_ctx = NULL;
}
return 0;
}
static bool usermgr_uci_validate_section(const char *str)
{
if (!*str)
return false;
for (; *str; str++) {
unsigned char c = *str;
if (isalnum(c) || c == '_')
continue;
return false;
}
return true;
}
static int usermgr_uci_init_ptr(struct uci_ptr *ptr, const char *package, const char *section, const char *option, const char *value)
{
memset(ptr, 0, sizeof(struct uci_ptr));
/* value */
if (value)
ptr->value = value;
ptr->package = package;
if (!ptr->package)
goto error;
ptr->section = section;
if (!ptr->section) {
ptr->target = UCI_TYPE_PACKAGE;
goto lastval;
}
ptr->option = option;
if (!ptr->option) {
ptr->target = UCI_TYPE_SECTION;
goto lastval;
} else
ptr->target = UCI_TYPE_OPTION;
lastval:
if (ptr->section && !usermgr_uci_validate_section(ptr->section))
ptr->flags |= UCI_LOOKUP_EXTENDED;
return 0;
error:
return -1;
}
struct uci_section *usermgr_uci_walk_section(const char *package, const char *section_type, struct uci_section *prev_section)
{
struct uci_ptr ptr;
struct uci_element *e;
struct uci_section *next_section;
if (section_type == NULL) {
if (prev_section) {
e = &prev_section->e;
if (e->list.next == &prev_section->package->sections)
return NULL;
e = container_of(e->list.next, struct uci_element, list);
next_section = uci_to_section(e);
return next_section;
} else {
if (usermgr_uci_init_ptr(&ptr, package, NULL, NULL, NULL))
return NULL;
if (uci_lookup_ptr(uci_ctx, &ptr, NULL, true) != UCI_OK)
return NULL;
if (ptr.p->sections.next == &ptr.p->sections)
return NULL;
e = container_of(ptr.p->sections.next, struct uci_element, list);
next_section = uci_to_section(e);
return next_section;
}
} else {
struct uci_list *ul = NULL, *shead = NULL;
if (prev_section) {
ul = &prev_section->e.list;
shead = &prev_section->package->sections;
} else {
if (usermgr_uci_init_ptr(&ptr, package, NULL, NULL, NULL))
return NULL;
if (uci_lookup_ptr(uci_ctx, &ptr, NULL, true) != UCI_OK)
return NULL;
ul = &ptr.p->sections;
shead = &ptr.p->sections;
}
while (ul->next != shead) {
e = container_of(ul->next, struct uci_element, list);
next_section = uci_to_section(e);
if (strcmp(next_section->type, section_type) == 0)
return next_section;
ul = ul->next;
}
return NULL;
}
return NULL;
}
static struct uci_element *usermgr_uci_lookup_list(struct uci_list *list, const char *name)
{
struct uci_element *e;
uci_foreach_element(list, e) {
if (!strcmp(e->name, name))
return e;
}
return NULL;
}
static int usermgr_uci_lookup_ptr_by_section(struct uci_ptr *ptr, struct uci_section *section, const char *option, const char *value)
{
struct uci_element *e;
memset(ptr, 0, sizeof(struct uci_ptr));
ptr->package = section->package->e.name;
ptr->section = section->e.name;
ptr->option = option;
ptr->value = value;
ptr->flags |= UCI_LOOKUP_DONE;
ptr->p = section->package;
ptr->s = section;
if (ptr->option) {
e = usermgr_uci_lookup_list(&ptr->s->options, ptr->option);
if (!e)
return UCI_OK;
ptr->o = uci_to_option(e);
ptr->last = e;
ptr->target = UCI_TYPE_OPTION;
} else {
ptr->last = &ptr->s->e;
ptr->target = UCI_TYPE_SECTION;
}
ptr->flags |= UCI_LOOKUP_COMPLETE;
return UCI_OK;
}
char *usermgr_uci_get_value_by_section(struct uci_section *section, const char *option)
{
struct uci_ptr ptr;
if (usermgr_uci_lookup_ptr_by_section(&ptr, section, option, NULL) != UCI_OK)
return "";
if (!ptr.o)
return "";
if (ptr.o->v.string)
return ptr.o->v.string;
else
return "";
}
char *usermgr_uci_set_value_by_section(struct uci_section *section, const char *option, const char *value)
{
struct uci_ptr ptr;
if (section == NULL)
return "";
if (usermgr_uci_lookup_ptr_by_section(&ptr, section, option, value) != UCI_OK)
return "";
if (uci_set(uci_ctx, &ptr) != UCI_OK)
return "";
if (uci_save(uci_ctx, ptr.p) != UCI_OK)
return "";
if (ptr.o && ptr.o->v.string)
return ptr.o->v.string;
return "";
}
struct uci_section *usermgr_uci_add_section(const char *package, const char *section_type)
{
struct uci_ptr ptr;
struct uci_section *s = NULL;
if (usermgr_uci_init_ptr(&ptr, package, NULL, NULL, NULL)) {
return NULL;
}
if (uci_lookup_ptr(uci_ctx, &ptr, NULL, true) != UCI_OK) {
return NULL;
}
if (uci_add_section(uci_ctx, ptr.p, section_type, &s) != UCI_OK) {
return NULL;
}
if (uci_save(uci_ctx, ptr.p) != UCI_OK)
return NULL;
return s;
}
int usermgr_uci_delete_by_section(struct uci_section *section, const char *option, const char *value)
{
struct uci_ptr ptr = {0};
if (section == NULL)
return -1;
if (usermgr_uci_lookup_ptr_by_section(&ptr, section, option, value) != UCI_OK)
return -1;
if (uci_delete(uci_ctx, &ptr) != UCI_OK)
return -1;
if (uci_save(uci_ctx, ptr.p) != UCI_OK)
return -1;
return 0;
}
bool check_section_exist_by_option(const char *conf_path, const char *package, const char *section_type, const char *option, const char *val_check)
{
struct uci_section *s = NULL;
bool ret = false;
if (conf_path == NULL || package == NULL || section_type == NULL || option == NULL || val_check == NULL)
return ret;
usermgr_uci_init(conf_path);
usermgr_uci_foreach_section(package, section_type, s) {
const char *val = usermgr_uci_get_value_by_section(s, option);
if (strcmp(val, val_check) == 0) {
ret = true;
break;
}
}
usermgr_uci_fini(NULL);
return ret;
}
struct uci_section *get_section_from_config(const char *conf_path, const char *package, const char *section_type, const char *sec_name)
{
struct uci_section *s = NULL;
if (conf_path == NULL || package == NULL || section_type == NULL || sec_name == NULL)
return s;
usermgr_uci_init(conf_path);
usermgr_uci_foreach_section(package, section_type, s) {
if (strcmp(s->e.name, sec_name) == 0) {
break;
}
}
usermgr_uci_fini(NULL);
return s;
}
void strip_newline(char *str)
{
if (str == NULL)
return;
char* end_str = str + strlen(str) - 1;
while (str <= end_str && *end_str == '\n') {
*end_str = '\0';
--end_str ;
}
}
static void get_shell_path(const char *shell, char **path)
{
char line[2048] = {0};
if (shell == NULL || path == NULL)
return;
// cppcheck-suppress cert-MSC24-C
FILE *fp = fopen("/etc/shells", "r");
if (fp == NULL)
return;
while (fgets(line, sizeof(line), fp)) {
strip_newline(line);
char *tmp = strrchr(line, '/');
if (tmp == NULL)
tmp = line;
else
tmp = tmp + 1;
if (strcmp(shell, tmp) == 0) {
bool sh_enabled = false;
struct uci_section *s = NULL;
usermgr_uci_foreach_section("users", "shell", s) {
const char *val = usermgr_uci_get_value_by_section(s, "name");
if (strcmp(val, shell) == 0) {
val = usermgr_uci_get_value_by_section(s, "enabled");
if (strlen(val) == 0)
sh_enabled = true;
else
sh_enabled = dmuci_string_to_boolean(val);
break;
}
}
if (sh_enabled == true) {
*path = strdup(line);
}
break;
}
}
fclose(fp);
return;
}
static bool valid_group(char *grp)
{
char line[2048] = {0};
bool ret = false;
if (grp == NULL || strlen(grp) == 0)
return ret;
// cppcheck-suppress cert-MSC24-C
FILE *fp = fopen("/etc/group", "r");
if (fp == NULL)
return ret;
int len = strlen(grp) + 2;
char tmp[len];
snprintf(tmp, sizeof(tmp), "%s:", grp);
while (fgets(line, sizeof(line), fp)) {
if (strncmp(line, tmp, len-1) == 0) {
ret = true;
break;
}
}
fclose(fp);
return ret;
}
bool user_exist(char *user_name)
{
char line[2048] = {0};
bool ret = false;
if (user_name == NULL || strlen(user_name) == 0)
return ret;
// cppcheck-suppress cert-MSC24-C
FILE *fp = fopen("/etc/passwd", "r");
if (fp == NULL)
return ret;
int len = strlen(user_name) + 2;
char tmp[len];
snprintf(tmp, sizeof(tmp), "%s:", user_name);
while (fgets(line, sizeof(line), fp)) {
if (strncmp(line, tmp, len-1) == 0) {
ret = true;
break;
}
}
fclose(fp);
return ret;
}
static void get_text_password(struct ubus_request *req, int type __attribute__((unused)), struct blob_attr *msg)
{
char **text = (char **)req->priv;
const struct blobmsg_policy p[1] = { {"value", BLOBMSG_TYPE_STRING} };
struct blob_attr *tb[1] = {0};
if (msg == NULL)
return;
blobmsg_parse(p, 1, tb, blobmsg_data(msg), blobmsg_len(msg));
if (!tb[0])
return;
char *val = blobmsg_get_string(tb[0]);
if (val == NULL || strlen(val) == 0)
return;
*text = strdup(val);
return;
}
static char *decrypt_password(const char *password)
{
uint32_t id = 0;
char *text = NULL;
struct blob_buf b = {0};
if (password == NULL)
return text;
struct ubus_context *ctx = ubus_connect(NULL);
if (ctx == NULL)
return text;
memset(&b, 0, sizeof(struct blob_buf));
blob_buf_init(&b, 0);
blobmsg_add_string(&b, "data", password);
if (!ubus_lookup_id(ctx, "bbf.secure", &id)) {
ubus_invoke(ctx, id, "decode", b.head, get_text_password, &text, 5000);
}
blob_buf_free(&b);
ubus_free(ctx);
return text;
}
int add_user(const char *user_name)
{
char cmd[256] = {0};
FILE *pp = NULL;
if (user_name == NULL || strlen(user_name) == 0)
return -1;
snprintf(cmd, sizeof(cmd), "adduser -D -H -s /bin/false %s", user_name);
pp = popen(cmd, "r"); // flawfinder: ignore
if (pp != NULL) {
pclose(pp);
return 0;
}
return -1;
}
int del_user(const char *user_name)
{
char cmd[256] = {0};
FILE *pp = NULL;
if (user_name == NULL || strlen(user_name) == 0)
return -1;
snprintf(cmd, sizeof(cmd), "userdel -f %s", user_name);
pp = popen(cmd, "r"); // flawfinder: ignore
if (pp != NULL) {
pclose(pp);
return 0;
}
return -1;
}
int enable_user(const char *user_name)
{
char cmd[256] = {0};
FILE *pp = NULL;
if (user_name == NULL || strlen(user_name) == 0)
return -1;
snprintf(cmd, sizeof(cmd), "usermod -U %s", user_name);
pp = popen(cmd, "r"); // flawfinder: ignore
if (pp == NULL)
return -1;
pclose(pp);
return 0;
}
int disable_user(const char *user_name)
{
char cmd[256] = {0};
FILE *pp = NULL;
if (user_name == NULL || strlen(user_name) == 0)
return -1;
snprintf(cmd, sizeof(cmd), "usermod -L %s", user_name);
pp = popen(cmd, "r"); // flawfinder: ignore
if (pp == NULL)
return -1;
pclose(pp);
return 0;
}
int change_username(const char *old_name, const char *new_name)
{
char cmd[256] = {0};
FILE *pp = NULL;
if (old_name == NULL || strlen(old_name) == 0 || new_name == NULL || strlen(new_name) == 0)
return -1;
snprintf(cmd, sizeof(cmd), "usermod -b -l %s %s", new_name, old_name);
pp = popen(cmd, "r"); // flawfinder: ignore
if (pp == NULL)
return -1;
pclose(pp);
return 0;
}
int change_password(const char *user_name, const char *password)
{
char cmd[256] = {0};
FILE *pp = NULL;
if (user_name == NULL || strlen(user_name) == 0 || password == NULL || strlen(password) == 0)
return -1;
char *text_pass = decrypt_password(password);
if (text_pass == NULL)
return -1;
snprintf(cmd, sizeof(cmd), "echo %s:'%s' | chpasswd", user_name, text_pass);
FREE(text_pass);
pp = popen(cmd, "r"); // flawfinder: ignore
if (pp == NULL)
return -1;
pclose(pp);
return 0;
}
int set_user_shell(const char *user_name, const char *shell)
{
char cmd[256] = {0};
FILE *pp = NULL;
if (user_name == NULL || strlen(user_name) == 0)
return -1;
snprintf(cmd, sizeof(cmd), "usermod -s /bin/false %s", user_name);
pp = popen(cmd, "r"); // flawfinder: ignore
if (pp == NULL)
return -1;
pclose(pp);
if (shell == NULL || strlen(shell) == 0 || strcmp(shell, "false") == 0)
return 0;
char *path = NULL;
get_shell_path(shell, &path);
if (path == NULL || strlen(path) == 0) {
FREE(path);
return -1;
}
snprintf(cmd, sizeof(cmd), "usermod -s %s %s", path, user_name);
FREE(path);
pp = popen(cmd, "r"); // flawfinder: ignore
if (pp == NULL)
return -1;
pclose(pp);
return 0;
}
int set_user_group(const char *user_name, const char *group)
{
char cmd[256] = {0};
FILE *pp = NULL;
char buff[2048] = {0};
char *tok = NULL, *ptr = NULL;
if (user_name == NULL || strlen(user_name) == 0)
return -1;
snprintf(cmd, sizeof(cmd), "usermod -G \"\" %s", user_name);
pp = popen(cmd, "r"); // flawfinder: ignore
if (pp == NULL)
return -1;
pclose(pp);
if (group == NULL || strlen(group) == 0)
return 0;
snprintf(buff, sizeof(buff), "%s", group);
for (tok = strtok_r(buff, ",", &ptr); tok != NULL; tok = strtok_r(NULL, ",", &ptr)) {
char *grp = NULL;
if (strncmp(tok, GROUP_PREFIX, strlen(GROUP_PREFIX)) == 0)
grp = tok + strlen(GROUP_PREFIX);
else
grp = tok;
if (!valid_group(grp))
continue;
snprintf(cmd, sizeof(cmd), "usermod -aG %s %s", grp, user_name);
pp = popen(cmd, "r"); // flawfinder: ignore
if (pp == NULL)
return -1;
pclose(pp);
}
return 0;
}
int add_group(const char *group_name)
{
char cmd[256] = {0};
FILE *pp = NULL;
const char *grp = NULL;
if (group_name == NULL || strlen(group_name) == 0)
return -1;
if (strncmp(group_name, GROUP_PREFIX, strlen(GROUP_PREFIX)) == 0)
grp = group_name + strlen(GROUP_PREFIX);
else
grp = group_name;
snprintf(cmd, sizeof(cmd), "groupadd -f %s", grp);
pp = popen(cmd, "r"); // flawfinder: ignore
if (pp != NULL) {
pclose(pp);
return 0;
}
return -1;
}
int del_group(const char *group_name)
{
char cmd[256] = {0};
FILE *pp = NULL;
const char *grp = NULL;
if (group_name == NULL || strlen(group_name) == 0)
return -1;
if (strncmp(group_name, GROUP_PREFIX, strlen(GROUP_PREFIX)) == 0)
grp = group_name + strlen(GROUP_PREFIX);
else
grp = group_name;
snprintf(cmd, sizeof(cmd), "groupdel -f %s", grp);
pp = popen(cmd, "r"); // flawfinder: ignore
if (pp != NULL) {
pclose(pp);
return 0;
}
return -1;
}
/*
* helper.h: uci utilities
*
* Copyright (C) 2024 IOPSYS Software Solutions AB. All rights reserved.
*
* Author: Suvendhu Hansa <suvendhu.hansa@iopsys.eu>
*
* See LICENSE file for license related information.
*/
#ifndef __HELPER_H
#define __HELPER_H
#include <uci.h>
int usermgr_uci_init(const char *conf_path);
int usermgr_uci_fini(const char *package_name);
struct uci_section *usermgr_uci_add_section(const char *package, const char *section_type);
int usermgr_uci_delete_by_section(struct uci_section *section, const char *option, const char *value);
char *usermgr_uci_get_value_by_section(struct uci_section *section, const char *option);
char *usermgr_uci_set_value_by_section(struct uci_section *section, const char *option, const char *value);
struct uci_section *usermgr_uci_walk_section(const char *package, const char *section_type, struct uci_section *prev_section);
bool check_section_exist_by_option(const char *conf_path, const char *package, const char *section_type, const char *option, const char *val_check);
struct uci_section *get_section_from_config(const char *conf_path, const char *package, const char *section_type, const char *sec_name);
#define usermgr_uci_foreach_section(package, section_type, section) \
for (section = usermgr_uci_walk_section(package, section_type, NULL); \
section != NULL; \
section = usermgr_uci_walk_section(package, section_type, section))
int add_user(const char *user_name);
int del_user(const char *user_name);
int enable_user(const char *user_name);
int disable_user(const char *user_name);
int change_username(const char *old_name, const char *new_name);
int change_password(const char *user_name, const char *password);
int set_user_shell(const char *user_name, const char *shell);
int set_user_group(const char *user_name, const char *group);
int add_group(const char *group_name);
int del_group(const char *group_name);
bool user_exist(char *user_name);
void strip_newline(char *str);
#endif //__HELPER_H
/*
* Copyright (C) 2024 iopsys Software Solutions AB
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation
*
* Author: Suvendhu Hansa <suvendhu.hansa@iopsys.eu>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libubus.h>
#include <libubox/uloop.h>
#include <libbbfdm-ubus/bbfdm-ubus.h>
#include "users.h"
#include "helper.h"
extern DM_MAP_OBJ tDynamicObj[];
static struct bbfdm_context bbfdm_ctx = {0};
static struct ubus_event_handler ev = {0};
static void get_user_shell_name(const char *username, char **shell)
{
char cmd[128] = {0};
if (username == NULL || shell == NULL)
return;
snprintf(cmd, sizeof(cmd), "cat /etc/passwd | grep -E \"^%s:\" | cut -d: -f7", username);
FILE *pp = popen(cmd, "r"); // flawfinder: ignore
if (pp != NULL) {
char line[2056] = {0};
if (fgets(line, sizeof(line), pp) != NULL) {
remove_new_line(line);
if (DM_STRCMP(line, "/bin/false") != 0) {
char *pos = strrchr(line, '/');
*shell = pos ? strdup(pos + 1) : strdup(line);
}
}
pclose(pp);
}
}
static void get_perticipated_groups(const char *username, char **groups)
{
char cmd[128] = {0};
if (username == NULL || groups == NULL)
return;
snprintf(cmd, sizeof(cmd), "groups %s", username);
FILE *pp = popen(cmd, "r"); // flawfinder: ignore
if (pp != NULL) {
char line[2056] = {0};
if (fgets(line, sizeof(line), pp) != NULL) {
remove_new_line(line);
if (DM_STRNCMP(line, "groups:", 7) != 0) {
*groups = strdup(line);
}
}
pclose(pp);
}
}
static void find_unique_role_id(char **id)
{
unsigned int i;
if (id == NULL)
return;
*id = NULL;
for (i = 0; i <= 0xFFFFFFFFU; i++) {
char str_role[64] = {0};
snprintf(str_role, sizeof(str_role), "%u", i);
if (check_section_exist_by_option(STD_UCI_PATH, "users", "role", "role_id", str_role) == false &&
check_section_exist_by_option(DMMAP_UCI_PATH, DMMAP_SYSTEM_USER_FILE, "role", "role_id", str_role) == false) {
*id = strdup(str_role);
break;
}
}
return;
}
static void sync_system_users_groups(FILE *pp, const char *package, const char *dmmap_package, const char *section_type, bool user_cfg)
{
char line[65] = {0};
if (pp == NULL || package == NULL || dmmap_package == NULL || section_type == NULL)
return;
while (fgets(line, sizeof(line), pp) != NULL) {
struct uci_section *dmmap_sect = NULL;
char name[70] = {0};
remove_new_line(line);
if (!user_cfg) {
snprintf(name, sizeof(name), "%s%s", GROUP_PREFIX, line);
} else {
snprintf(name, sizeof(name), "%s", line);
}
replace_special_char(name, '_');
if (get_section_from_config(STD_UCI_PATH, package, section_type, name) != NULL) {
continue;
}
if (check_section_exist_by_option(DMMAP_UCI_PATH, dmmap_package, section_type, "section_name", name) == false) {
// add to dmmap if not present in users as well as dmmap_system_users file
usermgr_uci_init(DMMAP_UCI_PATH);
dmmap_sect = usermgr_uci_add_section(dmmap_package, section_type);
if (dmmap_sect == NULL) {
usermgr_uci_fini(NULL);
continue;
}
usermgr_uci_set_value_by_section(dmmap_sect, "section_name", name);
usermgr_uci_set_value_by_section(dmmap_sect, "static", "1");
if (user_cfg) {
char *shell = NULL, *group = NULL;
get_user_shell_name(name, &shell);
if (shell) {
usermgr_uci_set_value_by_section(dmmap_sect, "shell", shell);
free(shell);
}
get_perticipated_groups(line, &group);
if (group) {
char *pch = NULL, *spch = NULL, lbuf[1024] = {0};
unsigned pos = 0;
for (pch = strtok_r(group, " ", &spch); pch != NULL; pch = strtok_r(NULL, " ", &spch)) {
if (strlen(pch) < (1024 - strlen(lbuf) - strlen(GROUP_PREFIX))) {
replace_special_char(pch, '_');
pos += snprintf(&lbuf[pos], sizeof(lbuf) - pos, "%s%s,", GROUP_PREFIX, pch);
}
}
if (pos)
lbuf[pos - 1] = 0;
usermgr_uci_set_value_by_section(dmmap_sect, "member_groups", lbuf);
free(group);
}
}
usermgr_uci_fini(dmmap_package);
}
}
}
static void sync_system_user(void)
{
char cmd[256] = {0};
snprintf(cmd, sizeof(cmd), "cat /etc/passwd | cut -d: -f1");
FILE *pp = popen(cmd, "r"); // flawfinder: ignore
if (pp != NULL) {
sync_system_users_groups(pp, "users", DMMAP_SYSTEM_USER_FILE, "user", true);
pclose(pp);
}
}
static void sync_system_group(void)
{
char cmd[256] = {0};
snprintf(cmd, sizeof(cmd), "cat /etc/group | cut -d: -f1");
FILE *pp = popen(cmd, "r"); // flawfinder: ignore
if (pp != NULL) {
sync_system_users_groups(pp, "users", DMMAP_SYSTEM_USER_FILE, "group", false);
pclose(pp);
}
}
static void sync_static_role(void)
{
DIR *directory;
directory = opendir("/etc/users/roles");
if (directory == NULL) {
return;
}
struct dirent *file;
char role_file[256] = {0};
while ((file = readdir(directory)) != NULL) {
char *tmp = NULL;
snprintf(role_file, sizeof(role_file), "%s", file->d_name);
tmp = strrchr(role_file, '.');
if (DM_STRCMP(tmp, ".json") != 0) {
continue;
}
*tmp = '\0';
if (check_section_exist_by_option(STD_UCI_PATH, "users", "role", "name", role_file) == true) {
continue;
}
if (check_section_exist_by_option(DMMAP_UCI_PATH, DMMAP_SYSTEM_USER_FILE, "role", "name", role_file) == false) {
// add to dmmap if not present in users as well as dmmap_system_users file
struct uci_section *dmmap_sect = NULL;
char *role_id = NULL;
find_unique_role_id(&role_id);
if (role_id == NULL)
continue;
usermgr_uci_init(DMMAP_UCI_PATH);
dmmap_sect = usermgr_uci_add_section(DMMAP_SYSTEM_USER_FILE, "role");
if (dmmap_sect == NULL) {
free(role_id);
usermgr_uci_fini(NULL);
continue;
}
usermgr_uci_set_value_by_section(dmmap_sect, "enabled", "1");
usermgr_uci_set_value_by_section(dmmap_sect, "role_id", role_id);
usermgr_uci_set_value_by_section(dmmap_sect, "static", "1");
usermgr_uci_set_value_by_section(dmmap_sect, "name", role_file);
free(role_id);
usermgr_uci_fini(DMMAP_SYSTEM_USER_FILE);
}
}
}
static void create_groups(void)
{
struct uci_section *s = NULL;
usermgr_uci_init(STD_UCI_PATH);
usermgr_uci_foreach_section("users", "group", s) {
char *group_name = NULL;
const char *val = NULL;
int len = strlen(GROUP_PREFIX);
if (strncmp(s->e.name, GROUP_PREFIX, len) == 0)
group_name = strdup(s->e.name + len);
else
group_name = strdup(s->e.name);
val = usermgr_uci_get_value_by_section(s, "enabled");
bool enable = dmuci_string_to_boolean(val);
val = usermgr_uci_get_value_by_section(s, "deleted");
bool deleted = dmuci_string_to_boolean(val);
const char *old_name = usermgr_uci_get_value_by_section(s, "old_name");
if (deleted) {
del_group(group_name);
usermgr_uci_delete_by_section(s, NULL, NULL);
FREE(group_name);
continue;
}
if (strlen(old_name) != 0) {
del_group(old_name);
usermgr_uci_set_value_by_section(s, "old_name", "");
}
if (enable) {
add_group(group_name);
} else {
del_group(group_name);
}
FREE(group_name);
}
usermgr_uci_fini("users");
}
static void create_users(void)
{
struct uci_section *s = NULL;
usermgr_uci_init(STD_UCI_PATH);
usermgr_uci_foreach_section("users", "user", s) {
const char *val = NULL;
char *user_name = strdup(s->e.name);
val = usermgr_uci_get_value_by_section(s, "enabled");
bool enable = dmuci_string_to_boolean(val);
val = usermgr_uci_get_value_by_section(s, "deleted");
bool deleted = dmuci_string_to_boolean(val);
const char *old_name = usermgr_uci_get_value_by_section(s, "old_name");
const char *member_groups = usermgr_uci_get_value_by_section(s, "member_groups");
const char *shell = usermgr_uci_get_value_by_section(s, "shell");
const char *enc_password = usermgr_uci_get_value_by_section(s, "encrypted_password");
if (deleted) {
del_user(user_name);
usermgr_uci_delete_by_section(s, NULL, NULL);
continue;
}
if (strlen(old_name) != 0) {
change_username(old_name, user_name);
usermgr_uci_set_value_by_section(s, "old_name", "");
}
if (!user_exist(user_name)) {
add_user(user_name);
}
if (strlen(enc_password) != 0) {
change_password(user_name, enc_password);
}
set_user_shell(user_name, shell);
set_user_group(user_name, member_groups);
if (enable)
enable_user(user_name);
else
disable_user(user_name);
FREE(user_name);
}
usermgr_uci_fini("users");
}
static void config_reload_cb(struct ubus_context *ctx __attribute__((unused)),
struct ubus_event_handler *ev __attribute__((unused)),
const char *type __attribute__((unused)),
struct blob_attr *msg __attribute__((unused)))
{
create_groups();
create_users();
}
static int register_config_change(struct ubus_context *uctx)
{
int ret;
memset(&ev, 0, sizeof(struct ubus_event_handler));
ev.cb = config_reload_cb;
ret = ubus_register_event_handler(uctx, &ev, "usermngr.reload");
if (ret)
return -1;
return 0;
}
int main(int argc, char **argv)
{
char fname[128] = {0};
snprintf(fname, sizeof(fname), "%s/%s", DMMAP_UCI_PATH, DMMAP_SYSTEM_USER_FILE);
if (!file_exists(fname)) {
// cppcheck-suppress cert-MSC24-C
FILE *fp = fopen(fname, "w");
if (fp) {
fclose(fp);
}
}
memset(&bbfdm_ctx, 0, sizeof(struct bbfdm_context));
sync_system_user();
sync_system_group();
sync_static_role();
create_groups();
create_users();
bbfdm_ubus_set_service_name(&bbfdm_ctx, "usermngr");
bbfdm_ubus_set_log_level(3);
bbfdm_ubus_load_data_model(tDynamicObj);
if (bbfdm_ubus_regiter_init(&bbfdm_ctx))
goto out;
if (register_config_change(&bbfdm_ctx.ubus_ctx) != 0)
goto out;
uloop_run();
out:
bbfdm_ubus_regiter_free(&bbfdm_ctx);
return 0;
}
......@@ -8,7 +8,6 @@
* Author: Suvendhu Hansa <suvendhu.hansa@iopsys.eu>
*/
#include <libbbfdm_api.h>
#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE
#endif
......@@ -22,8 +21,6 @@
#include "users.h"
#define DMMAP_SYSTEM_USER_FILE "dmmap_system_user"
enum group_operations {
NAME_CHANGE,
DELETE,
......@@ -438,139 +435,13 @@ static bool static_entry(struct uci_section *s)
return val;
}
static void get_user_shell_name(const char *username, char **shell)
{
char cmd[128] = {0};
if (username == NULL || shell == NULL)
return;
snprintf(cmd, sizeof(cmd), "cat /etc/passwd | grep -E \"^%s:\" | cut -d: -f7", username);
FILE *pp = popen(cmd, "r"); // flawfinder: ignore
if (pp != NULL) {
char line[2056] = {0};
if (fgets(line, sizeof(line), pp) != NULL) {
remove_new_line(line);
if (DM_STRCMP(line, "/bin/false") != 0) {
char *pos = strrchr(line, '/');
*shell = pos ? dmstrdup(pos + 1) : dmstrdup(line);
}
}
pclose(pp);
}
}
static void get_perticipated_groups(const char *username, char **groups)
{
char cmd[128] = {0};
if (username == NULL || groups == NULL)
return;
snprintf(cmd, sizeof(cmd), "groups %s", username);
FILE *pp = popen(cmd, "r"); // flawfinder: ignore
if (pp != NULL) {
char line[2056] = {0};
if (fgets(line, sizeof(line), pp) != NULL) {
remove_new_line(line);
if (DM_STRNCMP(line, "groups:", 7) != 0) {
*groups = dmstrdup(line);
}
}
pclose(pp);
}
}
static void sync_system_users_groups(FILE *pp, const char *package, const char *dmmap_package, const char *section_type, bool user_cfg, struct list_head *dup_list)
{
char line[65] = {0};
if (pp == NULL || package == NULL || dmmap_package == NULL || section_type == NULL || dup_list == NULL)
return;
while (fgets(line, sizeof(line), pp) != NULL) {
struct uci_section *dmmap_sect = NULL;
char name[70] = {0};
remove_new_line(line);
if (!user_cfg) {
snprintf(name, sizeof(name), "%s%s", GROUP_PREFIX, line);
} else {
snprintf(name, sizeof(name), "%s", line);
}
replace_special_char(name, '_');
if (get_origin_section_from_config(package, section_type, name) != NULL) {
continue;
}
if ((dmmap_sect = get_dup_section_in_dmmap(dmmap_package, section_type, name)) == NULL) {
// add to dmmap if not present in users as well as dmmap_system_users file
bbf_uci_add_section_bbfdm(dmmap_package, section_type, &dmmap_sect);
bbf_uci_set_value_by_section(dmmap_sect, "section_name", name);
bbf_uci_set_value_by_section(dmmap_sect, "static", "1");
if (user_cfg) {
char *shell = NULL, *group = NULL;
get_user_shell_name(name, &shell);
if (DM_STRLEN(shell) > 0)
bbf_uci_set_value_by_section(dmmap_sect, "shell", shell);
get_perticipated_groups(line, &group);
if (DM_STRLEN(group) > 0) {
char *pch = NULL, *spch = NULL, lbuf[1024] = {0};
unsigned pos = 0;
for (pch = strtok_r(group, " ", &spch); pch != NULL; pch = strtok_r(NULL, " ", &spch)) {
if (DM_STRLEN(pch) < (1024 - strlen(lbuf) - strlen(GROUP_PREFIX))) {
replace_special_char(pch, '_');
pos += snprintf(&lbuf[pos], sizeof(lbuf) - pos, "%s%s,", GROUP_PREFIX, pch);
}
}
if (pos)
lbuf[pos - 1] = 0;
bbf_uci_set_value_by_section(dmmap_sect, "member_groups", lbuf);
}
}
}
/*
* Add dmmap sections to the list
*/
add_dmmap_config_dup_list(dup_list, NULL, dmmap_sect);
}
}
static void synchronize_users_config_sections_with_dmmap(const char *package, const char *section_type, const char *dmmap_package, struct list_head *dup_list, bool bootstrap)
static void synchronize_users_config_sections_with_dmmap(const char *package, const char *section_type, const char *dmmap_package, struct list_head *dup_list)
{
struct uci_section *s, *stmp;
if (bootstrap == true) {
char cmd[256] = {0};
bool user_cfg;
/* first copy the static users or groups to dmmap */
if (DM_STRCMP(section_type, "user") == 0) {
snprintf(cmd, sizeof(cmd), "cat /etc/passwd | cut -d: -f1");
user_cfg = true;
} else {
snprintf(cmd, sizeof(cmd), "cat /etc/group | cut -d: -f1");
user_cfg = false;
}
FILE *pp = popen(cmd, "r"); // flawfinder: ignore
if (pp != NULL) {
sync_system_users_groups(pp, package, DMMAP_SYSTEM_USER_FILE, section_type, user_cfg, dup_list);
pclose(pp);
}
} else {
/* add sytem users or groups section in list */
uci_path_foreach_sections_safe(bbfdm, DMMAP_SYSTEM_USER_FILE, section_type, stmp, s) {
add_dmmap_config_dup_list(dup_list, NULL, s);
}
/* add sytem users or groups section in list */
uci_path_foreach_sections_safe(bbfdm, DMMAP_SYSTEM_USER_FILE, section_type, stmp, s) {
add_dmmap_config_dup_list(dup_list, NULL, s);
}
bbf_uci_foreach_sections(package, section_type, s) {
......@@ -615,58 +486,13 @@ static void synchronize_users_config_sections_with_dmmap(const char *package, co
}
}
static void synchronize_roles_config_sections_with_dmmap(const char *package, const char *section_type, const char *dmmap_package, struct list_head *dup_list, bool bootstrap)
static void synchronize_roles_config_sections_with_dmmap(const char *package, const char *section_type, const char *dmmap_package, struct list_head *dup_list)
{
struct uci_section *s, *stmp;
if (bootstrap == true) {
DIR *directory;
directory = opendir("/etc/users/roles");
if (directory != NULL) {
struct dirent *file;
char role_file[256] = {0};
while ((file = readdir(directory)) != NULL) {
char *tmp = NULL;
snprintf(role_file, sizeof(role_file), "%s", file->d_name);
tmp = strrchr(role_file, '.');
if (DM_STRCMP(tmp, ".json") != 0) {
continue;
}
*tmp = '\0';
if (get_dup_section_in_config_opt(package, section_type, "name", role_file) != NULL) {
continue;
}
struct uci_section *dmmap_sect = NULL;
if ((dmmap_sect = get_dup_section_in_dmmap_opt(DMMAP_SYSTEM_USER_FILE, section_type, "name", role_file)) == NULL) {
// add to dmmap if not present in users as well as dmmap_system_users file
char *role_id = NULL;
get_unique_role_id(&role_id);
if (role_id == NULL)
continue;
bbf_uci_add_section_bbfdm(DMMAP_SYSTEM_USER_FILE, section_type, &dmmap_sect);
bbf_uci_set_value_by_section(dmmap_sect, "enabled", "1");
bbf_uci_set_value_by_section(dmmap_sect, "role_id", role_id);
bbf_uci_set_value_by_section(dmmap_sect, "static", "1");
bbf_uci_set_value_by_section(dmmap_sect, "name", role_file);
}
/*
* Add dmmap sections to the list
*/
add_dmmap_config_dup_list(dup_list, NULL, dmmap_sect);
}
}
} else {
/* add static roles section in list */
uci_path_foreach_sections_safe(bbfdm, DMMAP_SYSTEM_USER_FILE, section_type, stmp, s) {
add_dmmap_config_dup_list(dup_list, NULL, s);
}
/* add static roles section in list */
uci_path_foreach_sections_safe(bbfdm, DMMAP_SYSTEM_USER_FILE, section_type, stmp, s) {
add_dmmap_config_dup_list(dup_list, NULL, s);
}
bbf_uci_foreach_sections(package, section_type, s) {
......@@ -707,15 +533,8 @@ static int browseUserInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_d
char *inst = NULL;
struct dm_data *p = NULL;
LIST_HEAD(dup_list);
bool bootstrap = false;
const char *filepath = "/var/run/user_bootstrap";
if (file_exists(filepath)) {
bootstrap = true;
remove(filepath);
}
synchronize_users_config_sections_with_dmmap("users", "user", "dmmap_users", &dup_list, bootstrap);
synchronize_users_config_sections_with_dmmap("users", "user", "dmmap_users", &dup_list);
list_for_each_entry(p, &dup_list, list) {
inst = handle_instance(dmctx, parent_node, p->dmmap_section, "user_instance", "user_alias");
......@@ -732,15 +551,8 @@ static int browseGroupInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_
char *inst = NULL;
struct dm_data *p = NULL;
LIST_HEAD(dup_list);
bool bootstrap = false;
const char *filepath = "/var/run/group_bootstrap";
if (file_exists(filepath)) {
bootstrap = true;
remove(filepath);
}
synchronize_users_config_sections_with_dmmap("users", "group", "dmmap_users", &dup_list, bootstrap);
synchronize_users_config_sections_with_dmmap("users", "group", "dmmap_users", &dup_list);
list_for_each_entry(p, &dup_list, list) {
inst = handle_instance(dmctx, parent_node, p->dmmap_section, "group_instance", "group_alias");
......@@ -775,15 +587,8 @@ static int browseRoleInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_d
struct dm_data *p = NULL;
char *inst = NULL;
LIST_HEAD(dup_list);
bool bootstrap = false;
const char *filepath = "/var/run/role_bootstrap";
if (file_exists(filepath)) {
bootstrap = true;
remove(filepath);
}
synchronize_roles_config_sections_with_dmmap("users", "role", "dmmap_users", &dup_list, bootstrap);
synchronize_roles_config_sections_with_dmmap("users", "role", "dmmap_users", &dup_list);
list_for_each_entry(p, &dup_list, list) {
inst = handle_instance(dmctx, parent_node, p->dmmap_section, "role_instance", "role_alias");
......
......@@ -11,9 +11,13 @@
#ifndef _USERS_H
#define _USERS_H
#include <libbbfdm_api.h>
#include <libbbfdm-api/dmcommon.h>
#define GROUP_PREFIX "G_"
#define DMMAP_SYSTEM_USER_FILE "dmmap_system_user"
#define DMMAP_UCI_PATH "/etc/bbfdm/dmmap"
#define STD_UCI_PATH "/etc/config"
extern DMOBJ tUsersObj[];
extern DMOBJ tDeviceUsersObj[];
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment