Message ID | 20220307013344.29064-6-ematsumiya@suse.de |
---|---|
State | New |
Headers | show |
Series | Unify all programs into a single binary "ksmbdctl" | expand |
2022-03-07 10:33 GMT+09:00, Enzo Matsumiya <ematsumiya@suse.de>: > Create user command in preparation for binary unification. > > Rename some variables to make them more relatable to user properties and > management. > > Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de> > --- > daemon/daemon.c | 12 +- > daemon/ipc.c | 6 +- > include/config_parser.h | 2 +- > include/ksmbdtools.h | 7 +- > lib/config_parser.c | 4 +- > user/Makefile.am | 2 +- > user/adduser.c | 180 ----------------------------- > user/user.c | 238 ++++++++++++++++++++++++++++++++++++++ > user/user_admin.c | 247 +++++++++++++++++++++------------------- > user/user_admin.h | 35 +++++- > 10 files changed, 417 insertions(+), 316 deletions(-) > delete mode 100644 user/adduser.c > create mode 100644 user/user.c > > diff --git a/daemon/daemon.c b/daemon/daemon.c > index 946f500bc977..50afbd2ed70d 100644 > --- a/daemon/daemon.c > +++ b/daemon/daemon.c > @@ -291,11 +291,11 @@ static int setup_signals(sighandler_t handler) > return 0; > } > > -static int parse_configs(char *pwddb, char *smbconf) > +static int parse_configs(char *db, char *smbconf) > { > int ret; > > - ret = cp_parse_pwddb(pwddb); > + ret = cp_parse_db(db); > if (ret == -ENOENT) { > pr_err("User database file does not exist. %s\n", > "Only guest sessions (if permitted) will work."); > @@ -395,7 +395,7 @@ static int worker_process_init(void) > goto out; > } > > - ret = parse_configs(global_conf.pwddb, global_conf.smbconf); > + ret = parse_configs(global_conf.db, global_conf.smbconf); > if (ret) { > pr_err("Failed to parse configuration files\n"); > goto out; > @@ -645,7 +645,7 @@ int main(int argc, char *argv[]) > > set_logger_app_name("ksmbd.daemon"); > memset(&global_conf, 0x00, sizeof(struct smbconf_global)); > - global_conf.pwddb = PATH_PWDDB; > + global_conf.db = PATH_USERS_DB; > global_conf.smbconf = PATH_SMBCONF; > pr_logger_init(PR_LOGGER_STDIO); > > @@ -669,7 +669,7 @@ int main(int argc, char *argv[]) > global_conf.smbconf = g_strdup(optarg); > break; > case 'u': > - global_conf.pwddb = g_strdup(optarg); > + global_conf.db = g_strdup(optarg); > break; > case 'n': > if (!optarg) > @@ -694,7 +694,7 @@ int main(int argc, char *argv[]) > } > } > > - if (!global_conf.smbconf || !global_conf.pwddb) { > + if (!global_conf.smbconf || !global_conf.db) { > pr_err("Out of memory\n"); > exit(EXIT_FAILURE); > } > diff --git a/daemon/ipc.c b/daemon/ipc.c > index c46cbc174175..b793a1e101b0 100644 > --- a/daemon/ipc.c > +++ b/daemon/ipc.c > @@ -63,13 +63,13 @@ static int generic_event(int type, void *payload, size_t > sz) > return 0; > } > > -static int parse_reload_configs(const char *pwddb, const char *smbconf) > +static int parse_reload_configs(const char *db, const char *smbconf) > { > int ret; > > pr_debug("Reload config\n"); > usm_remove_all_users(); > - ret = cp_parse_pwddb(pwddb); > + ret = cp_parse_db(db); > if (ret == -ENOENT) { > pr_err("User database file does not exist. %s\n", > "Only guest sessions (if permitted) will work."); > @@ -91,7 +91,7 @@ static int handle_generic_event(struct nl_cache_ops > *unused, > void *arg) > { > if (ksmbd_health_status & KSMBD_SHOULD_RELOAD_CONFIG) { > - parse_reload_configs(global_conf.pwddb, global_conf.smbconf); > + parse_reload_configs(global_conf.db, global_conf.smbconf); > ksmbd_health_status &= ~KSMBD_SHOULD_RELOAD_CONFIG; > } > > diff --git a/include/config_parser.h b/include/config_parser.h > index c051f487c319..0aefc3b4d5c7 100644 > --- a/include/config_parser.h > +++ b/include/config_parser.h > @@ -26,7 +26,7 @@ int cp_parse_external_smbconf_group(char *name, char > *opts); > int cp_smbconfig_hash_create(const char *smbconf); > void cp_smbconfig_destroy(void); > > -int cp_parse_pwddb(const char *pwddb); > +int cp_parse_db(const char *db); > int cp_parse_smbconf(const char *smbconf); > int cp_parse_reload_smbconf(const char *smbconf); > int cp_parse_subauth(const char *subauth_path); > diff --git a/include/ksmbdtools.h b/include/ksmbdtools.h > index fccb88d8898a..978cbe148eac 100644 > --- a/include/ksmbdtools.h > +++ b/include/ksmbdtools.h > @@ -57,7 +57,7 @@ struct smbconf_global { > unsigned int gen_subauth[3]; > char *krb5_keytab_file; > char *krb5_service_name; > - char *pwddb; > + char *db; > char *smbconf; > }; > > @@ -85,8 +85,9 @@ extern struct smbconf_global global_conf; > > #define KSMBD_CONF_FILE_MAX 10000 > > -#define PATH_PWDDB "/etc/ksmbd/ksmbdpwd.db" > -#define PATH_SMBCONF "/etc/ksmbd/smb.conf" > +#define PATH_USERS_DB "/etc/ksmbd/users.db" > +#define PATH_OLD_USERS_DB "/etc/ksmbd/ksmbdpwd.db" > +#define PATH_SMBCONF "/etc/ksmbd/smb.conf" > > #define KSMBD_HEALTH_START (0) > #define KSMBD_HEALTH_RUNNING (1 << 0) > diff --git a/lib/config_parser.c b/lib/config_parser.c > index 20e27c3ab8ec..a000a2a6059e 100644 > --- a/lib/config_parser.c > +++ b/lib/config_parser.c > @@ -680,9 +680,9 @@ int cp_parse_smbconf(const char *smbconf) > GROUPS_CALLBACK_STARTUP_INIT); > } > > -int cp_parse_pwddb(const char *pwddb) > +int cp_parse_db(const char *db) > { > - return __mmap_parse_file(pwddb, usm_add_update_user_from_pwdentry); > + return __mmap_parse_file(db, usm_add_update_user_from_pwdentry); > } > > int cp_smbconfig_hash_create(const char *smbconf) > diff --git a/user/Makefile.am b/user/Makefile.am > index c5cee686f5cc..ba491c84f0f4 100644 > --- a/user/Makefile.am > +++ b/user/Makefile.am > @@ -4,4 +4,4 @@ ksmbd_adduser_LDADD = $(top_builddir)/lib/libksmbdtools.a > > sbin_PROGRAMS = ksmbd.adduser > > -ksmbd_adduser_SOURCES = md4_hash.c user_admin.c adduser.c md4_hash.h > user_admin.h > +ksmbd_adduser_SOURCES = md4_hash.c user_admin.c user.c md4_hash.h > user_admin.h > diff --git a/user/adduser.c b/user/adduser.c > deleted file mode 100644 > index 88b12db9f439..000000000000 > --- a/user/adduser.c > +++ /dev/null > @@ -1,180 +0,0 @@ > -// SPDX-License-Identifier: GPL-2.0-or-later > -/* > - * Copyright (C) 2018 Samsung Electronics Co., Ltd. > - * > - * linux-cifsd-devel@lists.sourceforge.net > - */ > - > -#include <glib.h> > -#include <stdlib.h> > -#include <stdio.h> > -#include <unistd.h> > -#include <getopt.h> > -#include <sys/stat.h> > -#include <fcntl.h> > -#include <sys/types.h> > -#include <signal.h> > -#include <errno.h> > -#include <ctype.h> > - > -#include "config_parser.h" > -#include "ksmbdtools.h" > -#include "management/user.h" > -#include "management/share.h" > -#include "user_admin.h" > -#include "linux/ksmbd_server.h" > -#include "version.h" > - > -static char *arg_account = NULL; > -static char *arg_password = NULL; > - > -enum { > - COMMAND_ADD_USER = 1, > - COMMAND_DEL_USER, > - COMMAND_UPDATE_USER, > -}; > - > -static void usage(void) > -{ > - fprintf(stderr, "Usage: smbuseradd\n"); > - > - fprintf(stderr, "\t-a | --add-user=login\n"); > - fprintf(stderr, "\t-d | --del-user=login\n"); > - fprintf(stderr, "\t-u | --update-user=login\n"); > - fprintf(stderr, "\t-p | --password=pass\n"); > - > - fprintf(stderr, "\t-i smbpwd.db | --import-users=smbpwd.db\n"); > - fprintf(stderr, "\t-V | --version\n"); > - fprintf(stderr, "\t-v | --verbose\n"); > - > - exit(EXIT_FAILURE); > -} > - > -static void show_version(void) > -{ > - printf("ksmbd-tools version : %s\n", KSMBD_TOOLS_VERSION); > - exit(EXIT_FAILURE); > -} > - > -static int parse_configs(char *pwddb) > -{ > - int ret; > - > - ret = test_file_access(pwddb); > - if (ret) > - return ret; > - > - ret = cp_parse_pwddb(pwddb); > - if (ret) > - return ret; > - return 0; > -} > - > -static int sanity_check_user_name_simple(char *uname) > -{ > - int sz, i; > - > - if (!uname) > - return -EINVAL; > - > - sz = strlen(uname); > - if (sz < 1) > - return -EINVAL; > - if (sz >= KSMBD_REQ_MAX_ACCOUNT_NAME_SZ) > - return -EINVAL; > - > - /* 1'; Drop table users -- */ > - if (!strcmp(uname, "root")) > - return -EINVAL; > - > - if (strpbrk(uname, ":\n")) > - return -EINVAL; > - > - return 0; > -} > - > -int main(int argc, char *argv[]) > -{ > - int ret = EXIT_FAILURE; > - char *pwddb = PATH_PWDDB; > - int c, cmd = 0; > - > - set_logger_app_name("ksmbd.adduser"); > - > - opterr = 0; > - while ((c = getopt(argc, argv, "c:i:a:d:u:p:Vvh")) != EOF) > - switch (c) { > - case 'a': > - arg_account = g_strdup(optarg); > - cmd = COMMAND_ADD_USER; > - break; > - case 'd': > - arg_account = g_strdup(optarg); > - cmd = COMMAND_DEL_USER; > - break; > - case 'u': > - arg_account = g_strdup(optarg); > - cmd = COMMAND_UPDATE_USER; > - break; > - case 'p': > - arg_password = g_strdup(optarg); > - break; > - case 'i': > - pwddb = g_strdup(optarg); > - break; > - case 'V': > - show_version(); > - break; > - case 'v': > - break; > - case '?': > - case 'h': > - default: > - usage(); > - } > - > - if (sanity_check_user_name_simple(arg_account)) { > - pr_err("User name sanity check failure\n"); > - goto out; > - } > - > - if (!pwddb) { > - pr_err("Out of memory\n"); > - goto out; > - } > - > - ret = usm_init(); > - if (ret) { > - pr_err("Failed to init user management\n"); > - goto out; > - } > - > - ret = shm_init(); > - if (ret) { > - pr_err("Failed to init net share management\n"); > - goto out; > - } > - > - ret = parse_configs(pwddb); > - if (ret) { > - pr_err("Unable to parse configuration files\n"); > - goto out; > - } > - > - if (cmd == COMMAND_ADD_USER) > - ret = command_add_user(pwddb, arg_account, arg_password); > - if (cmd == COMMAND_DEL_USER) > - ret = command_del_user(pwddb, arg_account); > - if (cmd == COMMAND_UPDATE_USER) > - ret = command_update_user(pwddb, arg_account, arg_password); > - > - /* > - * We support only ADD_USER command at this moment > - */ > - if (ret == 0 && cmd == COMMAND_ADD_USER) > - notify_ksmbd_daemon(); > -out: > - shm_destroy(); > - usm_destroy(); > - return ret; > -} > diff --git a/user/user.c b/user/user.c > new file mode 100644 > index 000000000000..f59c34c11b02 > --- /dev/null > +++ b/user/user.c > @@ -0,0 +1,238 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > +/* > + * Copyright (C) 2018 Samsung Electronics Co., Ltd. > + * Copyright (C) 2021 SUSE LLC > + * > + * linux-cifsd-devel@lists.sourceforge.net > + */ > + > +#include <glib.h> > +#include <stdlib.h> > +#include <stdio.h> > +#include <unistd.h> > +#include <getopt.h> > +#include <sys/stat.h> > +#include <fcntl.h> > +#include <sys/types.h> > +#include <signal.h> > +#include <errno.h> > +#include <ctype.h> > + > +#include "config_parser.h" > +#include "ksmbdtools.h" > +#include "management/user.h" > +#include "management/share.h" > +#include "user_admin.h" > +#include "linux/ksmbd_server.h" > + > +static ksmbd_user_cmd ksmbd_user_get_cmd(char *cmd) > +{ > + int i; > + > + if (!cmd) > + return KSMBD_CMD_USER_NONE; > + > + for (i = 1; i < KSMBD_CMD_USER_MAX; i++) > + if (!strcmp(cmd, ksmbd_user_cmds_str[i])) > + return (ksmbd_user_cmd)i; > + > + return KSMBD_CMD_USER_NONE; > +} > + > +static const char *ksmbd_user_get_cmd_str(ksmbd_user_cmd cmd) > +{ > + if (cmd > KSMBD_CMD_USER_MAX) > + return ksmbd_user_cmds_str[KSMBD_CMD_USER_NONE]; > + > + return ksmbd_user_cmds_str[(int)cmd]; > +} > + > +void user_usage(ksmbd_user_cmd cmd) > +{ > + const char *cmd_str = ksmbd_user_get_cmd_str(cmd); > + > + switch (cmd) { > + case KSMBD_CMD_USER_ADD: > + case KSMBD_CMD_USER_UPDATE: > + pr_out("Usage: ksmbdctl user %s <username> [-p <password>] [-d > <file>]\n", cmd_str); > + pr_out("Adds or updates a user to the database.\n\n"); > + pr_out("%-30s%s", " -p, --password=<password>", "Use <password> for > <username>\n"); > + pr_out("%-30s%s", " -d, --database=<file>", "Use <file> as > database\n\n"); > + break; > + case KSMBD_CMD_USER_DELETE: > + pr_out("Usage: ksmbdctl user delete <username>\n"); > + pr_out("Delete user from database.\n\n"); > + break; > + case KSMBD_CMD_USER_LIST: > + pr_out("Usage: ksmbdctl user list\n"); > + pr_out("List users in database.\n\n"); > + pr_out("%-30s%s", " -d, --database=<file>", "Use <file> as > database\n\n"); > + break; > + default: > + pr_out("Usage: ksmbdctl user <subcommand> <args> [options]\n"); > + pr_out("User management.\n\n"); > + pr_out("List of available subcommands:\n"); > + pr_out("%-20s%s", " add", "Add a user\n"); > + pr_out("%-20s%s", " delete", "Delete a user\n"); > + pr_out("%-20s%s", " update", "Update an existing user\n"); > + pr_out("%-20s%s", " list", "List users in user database\n\n"); > + break; > + } > + > + exit(EXIT_FAILURE); > +} > + > +static int parse_configs(char *db) > +{ > + int ret; > + > + ret = test_file_access(db); > + if (ret) > + return ret; > + > + ret = cp_parse_db(db); > + if (ret) > + return ret; > + return 0; > +} > + > +static int sanity_check_user_name_simple(char *uname) > +{ > + int sz, i; > + > + if (!uname) > + return -EINVAL; > + > + sz = strlen(uname); > + if (sz < 1) > + return -EINVAL; > + if (sz >= KSMBD_REQ_MAX_ACCOUNT_NAME_SZ) > + return -EINVAL; > + > + /* 1'; Drop table users -- */ > + if (!strcmp(uname, "root")) > + return -EINVAL; > + > + for (i = 0; i < sz; i++) { > + if (isalnum(uname[i])) This check was removed before. Please remove this. > + return 0; > + } Is there any reason to remove the ":" check in uname using strpbrk() ? > + return -EINVAL; > +} > + > +int user_cmd(int argc, char *argv[]) > +{ > + int ret = EXIT_FAILURE; > + char *db = PATH_USERS_DB; > + char *login = NULL; > + char *pw = NULL; > + ksmbd_user_cmd cmd = KSMBD_CMD_USER_NONE; > + const char *cmd_str = NULL; > + int c; > + > + if (argc < 2) > + goto usage; > + > + set_logger_app_name("ksmbd-user"); > + > + cmd = ksmbd_user_get_cmd(argv[1]); > + cmd_str = ksmbd_user_get_cmd_str(cmd); > + > + if (cmd == KSMBD_CMD_USER_NONE) > + goto usage; > + > + if (cmd != KSMBD_CMD_USER_LIST) { > + if (argc == 2) > + goto missing_arg; > + > + if (argv[2][0] != '-') > + login = g_strdup(argv[2]); > + else > + goto usage; > + } > + > + optind = 1; > + while((c = getopt_long(argc, argv, "-:p:d:", user_opts, NULL)) != EOF) > + switch (c) { > + case 1: > + break; > + case 'p': > + pw = g_strdup(optarg); > + break; > + case 'd': > + db = g_strdup(optarg); > + break; > + case ':': > + case '?': > + default: > + goto usage; > + } > + > + if (cmd == KSMBD_CMD_USER_LIST) > + goto user_list; > + > + if (!login) > + goto missing_arg; > + > + if (sanity_check_user_name_simple(login)) { > + pr_err("User name (%s) sanity check failure\n"); You are missing adding "login" string to print %s here. > + goto out; > + } > + > +user_list: > + if (!db) { > + pr_err("Out of memory\n"); > + goto out; > + } > + > + ret = usm_init(); > + if (ret) { > + pr_err("Failed to init user management\n"); > + goto out; > + } > + > + ret = shm_init(); > + if (ret) { > + pr_err("Failed to init net share management\n"); > + goto out; > + } > + > + ret = parse_configs(db); > + if (ret) { > + pr_err("Unable to parse database file %s\n", db); > + goto out; > + } > + > + switch (cmd) { > + case KSMBD_CMD_USER_ADD: > + ret = user_add_cmd(db, login, pw); > + break; > + case KSMBD_CMD_USER_DELETE: > + ret = user_delete_cmd(db, login); > + break; > + case KSMBD_CMD_USER_UPDATE: > + ret = user_update_cmd(db, login, pw); > + break; > + case KSMBD_CMD_USER_LIST: > + ret = user_list_cmd(db); > + break; > + } > + > + /* > + * FIXME: We support only ADD_USER command at this moment > + */ > + if (ret == 0 && cmd == KSMBD_CMD_USER_ADD) > + notify_ksmbd_daemon(); > +out: > + shm_destroy(); > + usm_destroy(); > + return ret; > + > +missing_arg: > + if (cmd > KSMBD_CMD_USER_NONE && cmd < KSMBD_CMD_USER_MAX) > + pr_out("Subcommand \"%s\" requires an argument.\n\n", cmd_str); > +usage: > + user_usage(cmd); > + > + return ret; > +} > diff --git a/user/user_admin.c b/user/user_admin.c > index 95b05ea33f28..ca0e14978701 100644 > --- a/user/user_admin.c > +++ b/user/user_admin.c > @@ -1,6 +1,7 @@ > // SPDX-License-Identifier: GPL-2.0-or-later > /* > * Copyright (C) 2018 Samsung Electronics Co., Ltd. > + * Copyright (C) 2021 SUSE LLC > * > * linux-cifsd-devel@lists.sourceforge.net > */ > @@ -8,8 +9,8 @@ > #include <glib.h> > #include <stdlib.h> > #include <stdio.h> > +#include <stdbool.h> > #include <unistd.h> > -#include <getopt.h> > #include <sys/stat.h> > #include <fcntl.h> > #include <termios.h> > @@ -24,23 +25,23 @@ > > #define MAX_NT_PWD_LEN 129 > > -static char *arg_account = NULL; > -static char *arg_password = NULL; > static int conf_fd = -1; > static char wbuf[2 * MAX_NT_PWD_LEN + 2 * KSMBD_REQ_MAX_ACCOUNT_NAME_SZ]; > > -static int __opendb_file(char *pwddb) > +static int open_db(char *db, bool truncate) > { > - conf_fd = open(pwddb, O_WRONLY); > + conf_fd = open(db, O_WRONLY); > if (conf_fd == -1) { > - pr_err("%s %s\n", strerr(errno), pwddb); > + pr_err("%s %s\n", strerr(errno), db); > return -EINVAL; > } > > - if (ftruncate(conf_fd, 0)) { > - pr_err("%s %s\n", strerr(errno), pwddb); > - close(conf_fd); > - return -EINVAL; > + if (truncate) { > + if (ftruncate(conf_fd, 0)) { > + pr_err("%s %s\n", strerr(errno), db); > + close(conf_fd); > + return -EINVAL; > + } > } > > return 0; > @@ -60,149 +61,147 @@ static void term_toggle_echo(int on_off) > tcsetattr(STDIN_FILENO, TCSAFLUSH, &term); > } > > -static char *__prompt_password_stdin(size_t *sz) > +static char *prompt_password_stdin(size_t *sz) > { > - char *pswd1 = calloc(1, MAX_NT_PWD_LEN + 1); > - char *pswd2 = calloc(1, MAX_NT_PWD_LEN + 1); > + char *pw1 = calloc(1, MAX_NT_PWD_LEN + 1); > + char *pw2 = calloc(1, MAX_NT_PWD_LEN + 1); > size_t len = 0; > int i; > > - if (!pswd1 || !pswd2) { > - free(pswd1); > - free(pswd2); > - pr_err("Out of memory\n"); > - return NULL; > - } > + if (!pw1 || !pw2) > + goto fail; > > again: > - printf("New password: "); > + pr_out("New password: "); > term_toggle_echo(0); > - if (fgets(pswd1, MAX_NT_PWD_LEN, stdin) == NULL) { > + if (fgets(pw1, MAX_NT_PWD_LEN, stdin) == NULL) { > term_toggle_echo(1); > - pr_err("\nFatal error: %s\n", strerr(errno)); > - free(pswd1); > - free(pswd2); > - return NULL; > + pr_out("\n"); > + goto fail; > } > + pr_out("\n"); > > - printf("\nRetype new password: "); > - if (fgets(pswd2, MAX_NT_PWD_LEN, stdin) == NULL) { > + pr_out("Retype new password: "); > + if (fgets(pw2, MAX_NT_PWD_LEN, stdin) == NULL) { > term_toggle_echo(1); > - pr_err("\nFatal error: %s\n", strerr(errno)); > - free(pswd1); > - free(pswd2); > - return NULL; > + pr_out("\n"); > + goto fail; > } > term_toggle_echo(1); > - printf("\n"); > + pr_out("\n"); > > - len = strlen(pswd1); > + len = strlen(pw1); > for (i = 0; i < len; i++) > - if (pswd1[i] == '\n') > - pswd1[i] = 0x00; > + if (pw1[i] == '\n') > + pw1[i] = 0x00; > > - len = strlen(pswd2); > + len = strlen(pw2); > for (i = 0; i < len; i++) > - if (pswd2[i] == '\n') > - pswd2[i] = 0x00; > + if (pw2[i] == '\n') > + pw2[i] = 0x00; > > - if (memcmp(pswd1, pswd2, MAX_NT_PWD_LEN + 1)) { > + if (memcmp(pw1, pw2, MAX_NT_PWD_LEN + 1)) { > pr_err("Passwords don't match\n"); > goto again; > } > > - len = strlen(pswd1); > + len = strlen(pw1); > if (len <= 1) { > pr_err("No password was provided\n"); > goto again; > } > > *sz = len; > - free(pswd2); > - return pswd1; > + free(pw2); > + return pw1; > +fail: > + pr_err("Fatal error: %s\n", strerr(errno)); > + free(pw1); > + free(pw2); > + return NULL; > } > > -static char *prompt_password(size_t *sz) > +static char *prompt_password(char *password, size_t *len) > { > - if (!arg_password) > - return __prompt_password_stdin(sz); > + if (!password) > + return prompt_password_stdin(len); > > - *sz = strlen(arg_password); > - return arg_password; > + *len = strlen(password); > + return password; > } > > -static char *get_utf8_password(long *len) > +static char *get_utf8_password(char *password, long *len) > { > size_t raw_sz; > - char *pswd_raw, *pswd_converted; > + char *pw_raw, *pw_converted; > gsize bytes_read = 0; > gsize bytes_written = 0; > > - pswd_raw = prompt_password(&raw_sz); > - if (!pswd_raw) > + pw_raw = prompt_password(password, &raw_sz); > + if (!pw_raw) > return NULL; > > - pswd_converted = ksmbd_gconvert(pswd_raw, > + pw_converted = ksmbd_gconvert(pw_raw, > raw_sz, > KSMBD_CHARSET_UTF16LE, > KSMBD_CHARSET_DEFAULT, > &bytes_read, > &bytes_written); > - if (!pswd_converted) { > - free(pswd_raw); > + if (!pw_converted) { > + free(pw_raw); > return NULL; > } > > *len = bytes_written; > - free(pswd_raw); > - return pswd_converted; > + free(pw_raw); > + return pw_converted; > } > > -static void __sanity_check(char *pswd_hash, char *pswd_b64) > +static void sanity_check_pw(char *pw_hash, char *pw_b64) > { > - size_t pass_sz; > - char *pass = base64_decode(pswd_b64, &pass_sz); > + size_t len; > + char *pass = base64_decode(pw_b64, &len); > > if (!pass) { > pr_err("Unable to decode NT hash\n"); > exit(EXIT_FAILURE); > } > > - if (memcmp(pass, pswd_hash, pass_sz)) { > + if (memcmp(pass, pw_hash, len)) { > pr_err("NT hash encoding error\n"); > exit(EXIT_FAILURE); > } > free(pass); > } > > -static char *get_hashed_b64_password(void) > +static char *get_hashed_b64_password(char *password) > { > struct md4_ctx mctx; > long len; > - char *pswd_plain, *pswd_hash, *pswd_b64; > + char *pw_plain, *pw_hash, *pw_b64; > > - pswd_plain = get_utf8_password(&len); > - if (!pswd_plain) > + pw_plain = get_utf8_password(password, &len); > + if (!pw_plain) > return NULL; > > - pswd_hash = calloc(1, sizeof(mctx.hash) + 1); > - if (!pswd_hash) { > - free(pswd_plain); > + pw_hash = calloc(1, sizeof(mctx.hash) + 1); > + if (!pw_hash) { > + free(pw_plain); > pr_err("Out of memory\n"); > return NULL; > } > > md4_init(&mctx); > - md4_update(&mctx, pswd_plain, len); > - md4_final(&mctx, pswd_hash); > + md4_update(&mctx, pw_plain, len); > + md4_final(&mctx, pw_hash); > > - pswd_b64 = base64_encode(pswd_hash, > + pw_b64 = base64_encode(pw_hash, > MD4_HASH_WORDS * sizeof(unsigned int)); > > - __sanity_check(pswd_hash, pswd_b64); > - free(pswd_plain); > - free(pswd_hash); > - return pswd_b64; > + sanity_check_pw(pw_hash, pw_b64); > + free(pw_plain); > + free(pw_hash); > + return pw_b64; > } > > static void write_user(struct ksmbd_user *user) > @@ -248,7 +247,7 @@ static void write_remove_user_cb(gpointer key, > { > struct ksmbd_user *user = (struct ksmbd_user *)value; > > - if (!g_ascii_strcasecmp(user->name, arg_account)) { > + if (!g_ascii_strcasecmp(user->name, (char *)user_data)) { > pr_info("User '%s' removed\n", user->name); > return; > } > @@ -262,96 +261,91 @@ static void lookup_can_del_user(gpointer key, > { > struct ksmbd_share *share = (struct ksmbd_share *)value; > int ret = 0; > - int *abort_del_user = (int *)user_data; > + char *account = (char *)user_data; > > - if (*abort_del_user) > + if (!account) > return; > > ret = shm_lookup_users_map(share, > KSMBD_SHARE_ADMIN_USERS_MAP, > - arg_account); > + account); > if (ret == 0) > goto conflict; > > ret = shm_lookup_users_map(share, > KSMBD_SHARE_WRITE_LIST_MAP, > - arg_account); > + account); > if (ret == 0) > goto conflict; > > ret = shm_lookup_users_map(share, > KSMBD_SHARE_VALID_USERS_MAP, > - arg_account); > + account); > if (ret == 0) > goto conflict; > > - *abort_del_user = 0; > return; > > conflict: > pr_err("Share %s requires user %s to exist\n", > - share->name, arg_account); > - *abort_del_user = 1; > + share->name, account); > + account = NULL; > } > > -int command_add_user(char *pwddb, char *account, char *password) > +int user_add_cmd(char *db, char *account, char *password) > { > struct ksmbd_user *user; > - char *pswd; > - > - arg_account = account; > - arg_password = password; > + char *pw; > > - user = usm_lookup_user(arg_account); > + user = usm_lookup_user(account); > if (user) { > put_ksmbd_user(user); > - pr_err("Account `%s' already exists\n", arg_account); > + pr_err("Account `%s' already exists\n", account); > return -EEXIST; > } > > - pswd = get_hashed_b64_password(); > - if (!pswd) { > + pw = get_hashed_b64_password(password); > + if (!pw) { > pr_err("Out of memory\n"); > return -EINVAL; > } > > - /* pswd is already g_strdup-ed */ > - if (usm_add_new_user(arg_account, pswd)) { > + /* pw is already g_strdup-ed */ > + if (usm_add_new_user(account, pw)) { > pr_err("Could not add new account\n"); > return -EINVAL; > } > > - pr_info("User '%s' added\n", arg_account); > - if (__opendb_file(pwddb)) > + if (open_db(db, true)) > return -EINVAL; > > for_each_ksmbd_user(write_user_cb, NULL); > + > + pr_info("User '%s' added\n", account); > + > close(conf_fd); > return 0; > } > > -int command_update_user(char *pwddb, char *account, char *password) > +int user_update_cmd(char *db, char *account, char *password) > { > struct ksmbd_user *user; > - char *pswd; > - > - arg_password = password; > - arg_account = account; > + char *pw; > > - user = usm_lookup_user(arg_account); > + user = usm_lookup_user(account); > if (!user) { > - pr_err("Unknown account\n"); > + pr_err("Unknown account \"%s\"\n", account); > return -EINVAL; > } > > - pswd = get_hashed_b64_password(); > - if (!pswd) { > + pw = get_hashed_b64_password(password); > + if (!pw) { > pr_err("Out of memory\n"); > put_ksmbd_user(user); > return -EINVAL; > } > > - if (usm_update_user_password(user, pswd)) { > + if (usm_update_user_password(user, pw)) { > pr_err("Out of memory\n"); > put_ksmbd_user(user); > return -ENOMEM; > @@ -359,9 +353,9 @@ int command_update_user(char *pwddb, char *account, char > *password) > > pr_info("User '%s' updated\n", account); > put_ksmbd_user(user); > - free(pswd); > + free(pw); > > - if (__opendb_file(pwddb)) > + if (open_db(db, true)) > return -EINVAL; > > for_each_ksmbd_user(write_user_cb, NULL); > @@ -369,28 +363,47 @@ int command_update_user(char *pwddb, char *account, > char *password) > return 0; > } > > -int command_del_user(char *pwddb, char *account) > +int user_delete_cmd(char *db, char *account) > { > - int abort_del_user = 0; > + char *abort_del_user = strdup(account); > > - arg_account = account; > - if (!cp_key_cmp(global_conf.guest_account, arg_account)) { > + if (!cp_key_cmp(global_conf.guest_account, account)) { > pr_err("User %s is a global guest account. Abort deletion.\n", > - arg_account); > + account); > return -EINVAL; > } > > - for_each_ksmbd_share(lookup_can_del_user, &abort_del_user); > + for_each_ksmbd_share(lookup_can_del_user, abort_del_user); > > - if (abort_del_user) { > + if (!abort_del_user) { > pr_err("Aborting user deletion\n"); > return -EINVAL; > } > > - if (__opendb_file(pwddb)) > + if (open_db(db, true)) > + return -EINVAL; > + > + for_each_ksmbd_user(write_remove_user_cb, account); > + close(conf_fd); > + return 0; > +} > + > +static void list_users_cb(gpointer key, gpointer value, gpointer data) > +{ > + struct ksmbd_user *user = (struct ksmbd_user *)value; > + > + pr_out("%s\n", user->name); > +} > + > +int user_list_cmd(char *db) > +{ > + if (open_db(db, false)) > return -EINVAL; > > - for_each_ksmbd_user(write_remove_user_cb, NULL); > + pr_out("Users in %s:\n", db); > + for_each_ksmbd_user(list_users_cb, NULL); > + pr_out("\n"); > close(conf_fd); > + > return 0; > } > diff --git a/user/user_admin.h b/user/user_admin.h > index 9ff839e846bd..2dfbaa00b6b0 100644 > --- a/user/user_admin.h > +++ b/user/user_admin.h > @@ -1,6 +1,7 @@ > /* SPDX-License-Identifier: GPL-2.0-or-later */ > /* > * Copyright (C) 2018 Samsung Electronics Co., Ltd. > + * Copyright (C) 2021 SUSE LLC > * > * linux-cifsd-devel@lists.sourceforge.net > */ > @@ -8,8 +9,36 @@ > #ifndef __KSMBD_USER_ADMIN_H__ > #define __KSMBD_USER_ADMIN_H__ > > -int command_add_user(char *pwddb, char *account, char *password); > -int command_update_user(char *pwddb, char *account, char *password); > -int command_del_user(char *pwddb, char *account); > +int user_add_cmd(char *db, char *account, char *password); > +int user_delete_cmd(char *db, char *account); > +int user_update_cmd(char *db, char *account, char *password); > +int user_list_cmd(char *db); > + > +typedef enum { > + KSMBD_CMD_USER_NONE = 0, > + KSMBD_CMD_USER_ADD, > + KSMBD_CMD_USER_DELETE, > + KSMBD_CMD_USER_UPDATE, > + KSMBD_CMD_USER_LIST, > + KSMBD_CMD_USER_MAX > +} ksmbd_user_cmd; > + > +/* List of supported subcommands */ > +static const char *ksmbd_user_cmds_str[] = { > + "none", > + "add", > + "delete", > + "update", > + "list", > +}; > + > +static struct option user_opts[] = { > + { "password", required_argument, NULL, 'p' }, > + { "database", required_argument, NULL, 'd' }, > + { 0, 0, 0, 0 }, > +}; > + > +void user_usage(ksmbd_user_cmd cmd); > +int user_cmd(int argc, char *argv[]); > > #endif /* __KSMBD_USER_ADMIN_H__ */ > -- > 2.34.1 > >
diff --git a/daemon/daemon.c b/daemon/daemon.c index 946f500bc977..50afbd2ed70d 100644 --- a/daemon/daemon.c +++ b/daemon/daemon.c @@ -291,11 +291,11 @@ static int setup_signals(sighandler_t handler) return 0; } -static int parse_configs(char *pwddb, char *smbconf) +static int parse_configs(char *db, char *smbconf) { int ret; - ret = cp_parse_pwddb(pwddb); + ret = cp_parse_db(db); if (ret == -ENOENT) { pr_err("User database file does not exist. %s\n", "Only guest sessions (if permitted) will work."); @@ -395,7 +395,7 @@ static int worker_process_init(void) goto out; } - ret = parse_configs(global_conf.pwddb, global_conf.smbconf); + ret = parse_configs(global_conf.db, global_conf.smbconf); if (ret) { pr_err("Failed to parse configuration files\n"); goto out; @@ -645,7 +645,7 @@ int main(int argc, char *argv[]) set_logger_app_name("ksmbd.daemon"); memset(&global_conf, 0x00, sizeof(struct smbconf_global)); - global_conf.pwddb = PATH_PWDDB; + global_conf.db = PATH_USERS_DB; global_conf.smbconf = PATH_SMBCONF; pr_logger_init(PR_LOGGER_STDIO); @@ -669,7 +669,7 @@ int main(int argc, char *argv[]) global_conf.smbconf = g_strdup(optarg); break; case 'u': - global_conf.pwddb = g_strdup(optarg); + global_conf.db = g_strdup(optarg); break; case 'n': if (!optarg) @@ -694,7 +694,7 @@ int main(int argc, char *argv[]) } } - if (!global_conf.smbconf || !global_conf.pwddb) { + if (!global_conf.smbconf || !global_conf.db) { pr_err("Out of memory\n"); exit(EXIT_FAILURE); } diff --git a/daemon/ipc.c b/daemon/ipc.c index c46cbc174175..b793a1e101b0 100644 --- a/daemon/ipc.c +++ b/daemon/ipc.c @@ -63,13 +63,13 @@ static int generic_event(int type, void *payload, size_t sz) return 0; } -static int parse_reload_configs(const char *pwddb, const char *smbconf) +static int parse_reload_configs(const char *db, const char *smbconf) { int ret; pr_debug("Reload config\n"); usm_remove_all_users(); - ret = cp_parse_pwddb(pwddb); + ret = cp_parse_db(db); if (ret == -ENOENT) { pr_err("User database file does not exist. %s\n", "Only guest sessions (if permitted) will work."); @@ -91,7 +91,7 @@ static int handle_generic_event(struct nl_cache_ops *unused, void *arg) { if (ksmbd_health_status & KSMBD_SHOULD_RELOAD_CONFIG) { - parse_reload_configs(global_conf.pwddb, global_conf.smbconf); + parse_reload_configs(global_conf.db, global_conf.smbconf); ksmbd_health_status &= ~KSMBD_SHOULD_RELOAD_CONFIG; } diff --git a/include/config_parser.h b/include/config_parser.h index c051f487c319..0aefc3b4d5c7 100644 --- a/include/config_parser.h +++ b/include/config_parser.h @@ -26,7 +26,7 @@ int cp_parse_external_smbconf_group(char *name, char *opts); int cp_smbconfig_hash_create(const char *smbconf); void cp_smbconfig_destroy(void); -int cp_parse_pwddb(const char *pwddb); +int cp_parse_db(const char *db); int cp_parse_smbconf(const char *smbconf); int cp_parse_reload_smbconf(const char *smbconf); int cp_parse_subauth(const char *subauth_path); diff --git a/include/ksmbdtools.h b/include/ksmbdtools.h index fccb88d8898a..978cbe148eac 100644 --- a/include/ksmbdtools.h +++ b/include/ksmbdtools.h @@ -57,7 +57,7 @@ struct smbconf_global { unsigned int gen_subauth[3]; char *krb5_keytab_file; char *krb5_service_name; - char *pwddb; + char *db; char *smbconf; }; @@ -85,8 +85,9 @@ extern struct smbconf_global global_conf; #define KSMBD_CONF_FILE_MAX 10000 -#define PATH_PWDDB "/etc/ksmbd/ksmbdpwd.db" -#define PATH_SMBCONF "/etc/ksmbd/smb.conf" +#define PATH_USERS_DB "/etc/ksmbd/users.db" +#define PATH_OLD_USERS_DB "/etc/ksmbd/ksmbdpwd.db" +#define PATH_SMBCONF "/etc/ksmbd/smb.conf" #define KSMBD_HEALTH_START (0) #define KSMBD_HEALTH_RUNNING (1 << 0) diff --git a/lib/config_parser.c b/lib/config_parser.c index 20e27c3ab8ec..a000a2a6059e 100644 --- a/lib/config_parser.c +++ b/lib/config_parser.c @@ -680,9 +680,9 @@ int cp_parse_smbconf(const char *smbconf) GROUPS_CALLBACK_STARTUP_INIT); } -int cp_parse_pwddb(const char *pwddb) +int cp_parse_db(const char *db) { - return __mmap_parse_file(pwddb, usm_add_update_user_from_pwdentry); + return __mmap_parse_file(db, usm_add_update_user_from_pwdentry); } int cp_smbconfig_hash_create(const char *smbconf) diff --git a/user/Makefile.am b/user/Makefile.am index c5cee686f5cc..ba491c84f0f4 100644 --- a/user/Makefile.am +++ b/user/Makefile.am @@ -4,4 +4,4 @@ ksmbd_adduser_LDADD = $(top_builddir)/lib/libksmbdtools.a sbin_PROGRAMS = ksmbd.adduser -ksmbd_adduser_SOURCES = md4_hash.c user_admin.c adduser.c md4_hash.h user_admin.h +ksmbd_adduser_SOURCES = md4_hash.c user_admin.c user.c md4_hash.h user_admin.h diff --git a/user/adduser.c b/user/adduser.c deleted file mode 100644 index 88b12db9f439..000000000000 --- a/user/adduser.c +++ /dev/null @@ -1,180 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - * - * linux-cifsd-devel@lists.sourceforge.net - */ - -#include <glib.h> -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> -#include <getopt.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/types.h> -#include <signal.h> -#include <errno.h> -#include <ctype.h> - -#include "config_parser.h" -#include "ksmbdtools.h" -#include "management/user.h" -#include "management/share.h" -#include "user_admin.h" -#include "linux/ksmbd_server.h" -#include "version.h" - -static char *arg_account = NULL; -static char *arg_password = NULL; - -enum { - COMMAND_ADD_USER = 1, - COMMAND_DEL_USER, - COMMAND_UPDATE_USER, -}; - -static void usage(void) -{ - fprintf(stderr, "Usage: smbuseradd\n"); - - fprintf(stderr, "\t-a | --add-user=login\n"); - fprintf(stderr, "\t-d | --del-user=login\n"); - fprintf(stderr, "\t-u | --update-user=login\n"); - fprintf(stderr, "\t-p | --password=pass\n"); - - fprintf(stderr, "\t-i smbpwd.db | --import-users=smbpwd.db\n"); - fprintf(stderr, "\t-V | --version\n"); - fprintf(stderr, "\t-v | --verbose\n"); - - exit(EXIT_FAILURE); -} - -static void show_version(void) -{ - printf("ksmbd-tools version : %s\n", KSMBD_TOOLS_VERSION); - exit(EXIT_FAILURE); -} - -static int parse_configs(char *pwddb) -{ - int ret; - - ret = test_file_access(pwddb); - if (ret) - return ret; - - ret = cp_parse_pwddb(pwddb); - if (ret) - return ret; - return 0; -} - -static int sanity_check_user_name_simple(char *uname) -{ - int sz, i; - - if (!uname) - return -EINVAL; - - sz = strlen(uname); - if (sz < 1) - return -EINVAL; - if (sz >= KSMBD_REQ_MAX_ACCOUNT_NAME_SZ) - return -EINVAL; - - /* 1'; Drop table users -- */ - if (!strcmp(uname, "root")) - return -EINVAL; - - if (strpbrk(uname, ":\n")) - return -EINVAL; - - return 0; -} - -int main(int argc, char *argv[]) -{ - int ret = EXIT_FAILURE; - char *pwddb = PATH_PWDDB; - int c, cmd = 0; - - set_logger_app_name("ksmbd.adduser"); - - opterr = 0; - while ((c = getopt(argc, argv, "c:i:a:d:u:p:Vvh")) != EOF) - switch (c) { - case 'a': - arg_account = g_strdup(optarg); - cmd = COMMAND_ADD_USER; - break; - case 'd': - arg_account = g_strdup(optarg); - cmd = COMMAND_DEL_USER; - break; - case 'u': - arg_account = g_strdup(optarg); - cmd = COMMAND_UPDATE_USER; - break; - case 'p': - arg_password = g_strdup(optarg); - break; - case 'i': - pwddb = g_strdup(optarg); - break; - case 'V': - show_version(); - break; - case 'v': - break; - case '?': - case 'h': - default: - usage(); - } - - if (sanity_check_user_name_simple(arg_account)) { - pr_err("User name sanity check failure\n"); - goto out; - } - - if (!pwddb) { - pr_err("Out of memory\n"); - goto out; - } - - ret = usm_init(); - if (ret) { - pr_err("Failed to init user management\n"); - goto out; - } - - ret = shm_init(); - if (ret) { - pr_err("Failed to init net share management\n"); - goto out; - } - - ret = parse_configs(pwddb); - if (ret) { - pr_err("Unable to parse configuration files\n"); - goto out; - } - - if (cmd == COMMAND_ADD_USER) - ret = command_add_user(pwddb, arg_account, arg_password); - if (cmd == COMMAND_DEL_USER) - ret = command_del_user(pwddb, arg_account); - if (cmd == COMMAND_UPDATE_USER) - ret = command_update_user(pwddb, arg_account, arg_password); - - /* - * We support only ADD_USER command at this moment - */ - if (ret == 0 && cmd == COMMAND_ADD_USER) - notify_ksmbd_daemon(); -out: - shm_destroy(); - usm_destroy(); - return ret; -} diff --git a/user/user.c b/user/user.c new file mode 100644 index 000000000000..f59c34c11b02 --- /dev/null +++ b/user/user.c @@ -0,0 +1,238 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2018 Samsung Electronics Co., Ltd. + * Copyright (C) 2021 SUSE LLC + * + * linux-cifsd-devel@lists.sourceforge.net + */ + +#include <glib.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <getopt.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/types.h> +#include <signal.h> +#include <errno.h> +#include <ctype.h> + +#include "config_parser.h" +#include "ksmbdtools.h" +#include "management/user.h" +#include "management/share.h" +#include "user_admin.h" +#include "linux/ksmbd_server.h" + +static ksmbd_user_cmd ksmbd_user_get_cmd(char *cmd) +{ + int i; + + if (!cmd) + return KSMBD_CMD_USER_NONE; + + for (i = 1; i < KSMBD_CMD_USER_MAX; i++) + if (!strcmp(cmd, ksmbd_user_cmds_str[i])) + return (ksmbd_user_cmd)i; + + return KSMBD_CMD_USER_NONE; +} + +static const char *ksmbd_user_get_cmd_str(ksmbd_user_cmd cmd) +{ + if (cmd > KSMBD_CMD_USER_MAX) + return ksmbd_user_cmds_str[KSMBD_CMD_USER_NONE]; + + return ksmbd_user_cmds_str[(int)cmd]; +} + +void user_usage(ksmbd_user_cmd cmd) +{ + const char *cmd_str = ksmbd_user_get_cmd_str(cmd); + + switch (cmd) { + case KSMBD_CMD_USER_ADD: + case KSMBD_CMD_USER_UPDATE: + pr_out("Usage: ksmbdctl user %s <username> [-p <password>] [-d <file>]\n", cmd_str); + pr_out("Adds or updates a user to the database.\n\n"); + pr_out("%-30s%s", " -p, --password=<password>", "Use <password> for <username>\n"); + pr_out("%-30s%s", " -d, --database=<file>", "Use <file> as database\n\n"); + break; + case KSMBD_CMD_USER_DELETE: + pr_out("Usage: ksmbdctl user delete <username>\n"); + pr_out("Delete user from database.\n\n"); + break; + case KSMBD_CMD_USER_LIST: + pr_out("Usage: ksmbdctl user list\n"); + pr_out("List users in database.\n\n"); + pr_out("%-30s%s", " -d, --database=<file>", "Use <file> as database\n\n"); + break; + default: + pr_out("Usage: ksmbdctl user <subcommand> <args> [options]\n"); + pr_out("User management.\n\n"); + pr_out("List of available subcommands:\n"); + pr_out("%-20s%s", " add", "Add a user\n"); + pr_out("%-20s%s", " delete", "Delete a user\n"); + pr_out("%-20s%s", " update", "Update an existing user\n"); + pr_out("%-20s%s", " list", "List users in user database\n\n"); + break; + } + + exit(EXIT_FAILURE); +} + +static int parse_configs(char *db) +{ + int ret; + + ret = test_file_access(db); + if (ret) + return ret; + + ret = cp_parse_db(db); + if (ret) + return ret; + return 0; +} + +static int sanity_check_user_name_simple(char *uname) +{ + int sz, i; + + if (!uname) + return -EINVAL; + + sz = strlen(uname); + if (sz < 1) + return -EINVAL; + if (sz >= KSMBD_REQ_MAX_ACCOUNT_NAME_SZ) + return -EINVAL; + + /* 1'; Drop table users -- */ + if (!strcmp(uname, "root")) + return -EINVAL; + + for (i = 0; i < sz; i++) { + if (isalnum(uname[i])) + return 0; + } + return -EINVAL; +} + +int user_cmd(int argc, char *argv[]) +{ + int ret = EXIT_FAILURE; + char *db = PATH_USERS_DB; + char *login = NULL; + char *pw = NULL; + ksmbd_user_cmd cmd = KSMBD_CMD_USER_NONE; + const char *cmd_str = NULL; + int c; + + if (argc < 2) + goto usage; + + set_logger_app_name("ksmbd-user"); + + cmd = ksmbd_user_get_cmd(argv[1]); + cmd_str = ksmbd_user_get_cmd_str(cmd); + + if (cmd == KSMBD_CMD_USER_NONE) + goto usage; + + if (cmd != KSMBD_CMD_USER_LIST) { + if (argc == 2) + goto missing_arg; + + if (argv[2][0] != '-') + login = g_strdup(argv[2]); + else + goto usage; + } + + optind = 1; + while((c = getopt_long(argc, argv, "-:p:d:", user_opts, NULL)) != EOF) + switch (c) { + case 1: + break; + case 'p': + pw = g_strdup(optarg); + break; + case 'd': + db = g_strdup(optarg); + break; + case ':': + case '?': + default: + goto usage; + } + + if (cmd == KSMBD_CMD_USER_LIST) + goto user_list; + + if (!login) + goto missing_arg; + + if (sanity_check_user_name_simple(login)) { + pr_err("User name (%s) sanity check failure\n"); + goto out; + } + +user_list: + if (!db) { + pr_err("Out of memory\n"); + goto out; + } + + ret = usm_init(); + if (ret) { + pr_err("Failed to init user management\n"); + goto out; + } + + ret = shm_init(); + if (ret) { + pr_err("Failed to init net share management\n"); + goto out; + } + + ret = parse_configs(db); + if (ret) { + pr_err("Unable to parse database file %s\n", db); + goto out; + } + + switch (cmd) { + case KSMBD_CMD_USER_ADD: + ret = user_add_cmd(db, login, pw); + break; + case KSMBD_CMD_USER_DELETE: + ret = user_delete_cmd(db, login); + break; + case KSMBD_CMD_USER_UPDATE: + ret = user_update_cmd(db, login, pw); + break; + case KSMBD_CMD_USER_LIST: + ret = user_list_cmd(db); + break; + } + + /* + * FIXME: We support only ADD_USER command at this moment + */ + if (ret == 0 && cmd == KSMBD_CMD_USER_ADD) + notify_ksmbd_daemon(); +out: + shm_destroy(); + usm_destroy(); + return ret; + +missing_arg: + if (cmd > KSMBD_CMD_USER_NONE && cmd < KSMBD_CMD_USER_MAX) + pr_out("Subcommand \"%s\" requires an argument.\n\n", cmd_str); +usage: + user_usage(cmd); + + return ret; +} diff --git a/user/user_admin.c b/user/user_admin.c index 95b05ea33f28..ca0e14978701 100644 --- a/user/user_admin.c +++ b/user/user_admin.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2018 Samsung Electronics Co., Ltd. + * Copyright (C) 2021 SUSE LLC * * linux-cifsd-devel@lists.sourceforge.net */ @@ -8,8 +9,8 @@ #include <glib.h> #include <stdlib.h> #include <stdio.h> +#include <stdbool.h> #include <unistd.h> -#include <getopt.h> #include <sys/stat.h> #include <fcntl.h> #include <termios.h> @@ -24,23 +25,23 @@ #define MAX_NT_PWD_LEN 129 -static char *arg_account = NULL; -static char *arg_password = NULL; static int conf_fd = -1; static char wbuf[2 * MAX_NT_PWD_LEN + 2 * KSMBD_REQ_MAX_ACCOUNT_NAME_SZ]; -static int __opendb_file(char *pwddb) +static int open_db(char *db, bool truncate) { - conf_fd = open(pwddb, O_WRONLY); + conf_fd = open(db, O_WRONLY); if (conf_fd == -1) { - pr_err("%s %s\n", strerr(errno), pwddb); + pr_err("%s %s\n", strerr(errno), db); return -EINVAL; } - if (ftruncate(conf_fd, 0)) { - pr_err("%s %s\n", strerr(errno), pwddb); - close(conf_fd); - return -EINVAL; + if (truncate) { + if (ftruncate(conf_fd, 0)) { + pr_err("%s %s\n", strerr(errno), db); + close(conf_fd); + return -EINVAL; + } } return 0; @@ -60,149 +61,147 @@ static void term_toggle_echo(int on_off) tcsetattr(STDIN_FILENO, TCSAFLUSH, &term); } -static char *__prompt_password_stdin(size_t *sz) +static char *prompt_password_stdin(size_t *sz) { - char *pswd1 = calloc(1, MAX_NT_PWD_LEN + 1); - char *pswd2 = calloc(1, MAX_NT_PWD_LEN + 1); + char *pw1 = calloc(1, MAX_NT_PWD_LEN + 1); + char *pw2 = calloc(1, MAX_NT_PWD_LEN + 1); size_t len = 0; int i; - if (!pswd1 || !pswd2) { - free(pswd1); - free(pswd2); - pr_err("Out of memory\n"); - return NULL; - } + if (!pw1 || !pw2) + goto fail; again: - printf("New password: "); + pr_out("New password: "); term_toggle_echo(0); - if (fgets(pswd1, MAX_NT_PWD_LEN, stdin) == NULL) { + if (fgets(pw1, MAX_NT_PWD_LEN, stdin) == NULL) { term_toggle_echo(1); - pr_err("\nFatal error: %s\n", strerr(errno)); - free(pswd1); - free(pswd2); - return NULL; + pr_out("\n"); + goto fail; } + pr_out("\n"); - printf("\nRetype new password: "); - if (fgets(pswd2, MAX_NT_PWD_LEN, stdin) == NULL) { + pr_out("Retype new password: "); + if (fgets(pw2, MAX_NT_PWD_LEN, stdin) == NULL) { term_toggle_echo(1); - pr_err("\nFatal error: %s\n", strerr(errno)); - free(pswd1); - free(pswd2); - return NULL; + pr_out("\n"); + goto fail; } term_toggle_echo(1); - printf("\n"); + pr_out("\n"); - len = strlen(pswd1); + len = strlen(pw1); for (i = 0; i < len; i++) - if (pswd1[i] == '\n') - pswd1[i] = 0x00; + if (pw1[i] == '\n') + pw1[i] = 0x00; - len = strlen(pswd2); + len = strlen(pw2); for (i = 0; i < len; i++) - if (pswd2[i] == '\n') - pswd2[i] = 0x00; + if (pw2[i] == '\n') + pw2[i] = 0x00; - if (memcmp(pswd1, pswd2, MAX_NT_PWD_LEN + 1)) { + if (memcmp(pw1, pw2, MAX_NT_PWD_LEN + 1)) { pr_err("Passwords don't match\n"); goto again; } - len = strlen(pswd1); + len = strlen(pw1); if (len <= 1) { pr_err("No password was provided\n"); goto again; } *sz = len; - free(pswd2); - return pswd1; + free(pw2); + return pw1; +fail: + pr_err("Fatal error: %s\n", strerr(errno)); + free(pw1); + free(pw2); + return NULL; } -static char *prompt_password(size_t *sz) +static char *prompt_password(char *password, size_t *len) { - if (!arg_password) - return __prompt_password_stdin(sz); + if (!password) + return prompt_password_stdin(len); - *sz = strlen(arg_password); - return arg_password; + *len = strlen(password); + return password; } -static char *get_utf8_password(long *len) +static char *get_utf8_password(char *password, long *len) { size_t raw_sz; - char *pswd_raw, *pswd_converted; + char *pw_raw, *pw_converted; gsize bytes_read = 0; gsize bytes_written = 0; - pswd_raw = prompt_password(&raw_sz); - if (!pswd_raw) + pw_raw = prompt_password(password, &raw_sz); + if (!pw_raw) return NULL; - pswd_converted = ksmbd_gconvert(pswd_raw, + pw_converted = ksmbd_gconvert(pw_raw, raw_sz, KSMBD_CHARSET_UTF16LE, KSMBD_CHARSET_DEFAULT, &bytes_read, &bytes_written); - if (!pswd_converted) { - free(pswd_raw); + if (!pw_converted) { + free(pw_raw); return NULL; } *len = bytes_written; - free(pswd_raw); - return pswd_converted; + free(pw_raw); + return pw_converted; } -static void __sanity_check(char *pswd_hash, char *pswd_b64) +static void sanity_check_pw(char *pw_hash, char *pw_b64) { - size_t pass_sz; - char *pass = base64_decode(pswd_b64, &pass_sz); + size_t len; + char *pass = base64_decode(pw_b64, &len); if (!pass) { pr_err("Unable to decode NT hash\n"); exit(EXIT_FAILURE); } - if (memcmp(pass, pswd_hash, pass_sz)) { + if (memcmp(pass, pw_hash, len)) { pr_err("NT hash encoding error\n"); exit(EXIT_FAILURE); } free(pass); } -static char *get_hashed_b64_password(void) +static char *get_hashed_b64_password(char *password) { struct md4_ctx mctx; long len; - char *pswd_plain, *pswd_hash, *pswd_b64; + char *pw_plain, *pw_hash, *pw_b64; - pswd_plain = get_utf8_password(&len); - if (!pswd_plain) + pw_plain = get_utf8_password(password, &len); + if (!pw_plain) return NULL; - pswd_hash = calloc(1, sizeof(mctx.hash) + 1); - if (!pswd_hash) { - free(pswd_plain); + pw_hash = calloc(1, sizeof(mctx.hash) + 1); + if (!pw_hash) { + free(pw_plain); pr_err("Out of memory\n"); return NULL; } md4_init(&mctx); - md4_update(&mctx, pswd_plain, len); - md4_final(&mctx, pswd_hash); + md4_update(&mctx, pw_plain, len); + md4_final(&mctx, pw_hash); - pswd_b64 = base64_encode(pswd_hash, + pw_b64 = base64_encode(pw_hash, MD4_HASH_WORDS * sizeof(unsigned int)); - __sanity_check(pswd_hash, pswd_b64); - free(pswd_plain); - free(pswd_hash); - return pswd_b64; + sanity_check_pw(pw_hash, pw_b64); + free(pw_plain); + free(pw_hash); + return pw_b64; } static void write_user(struct ksmbd_user *user) @@ -248,7 +247,7 @@ static void write_remove_user_cb(gpointer key, { struct ksmbd_user *user = (struct ksmbd_user *)value; - if (!g_ascii_strcasecmp(user->name, arg_account)) { + if (!g_ascii_strcasecmp(user->name, (char *)user_data)) { pr_info("User '%s' removed\n", user->name); return; } @@ -262,96 +261,91 @@ static void lookup_can_del_user(gpointer key, { struct ksmbd_share *share = (struct ksmbd_share *)value; int ret = 0; - int *abort_del_user = (int *)user_data; + char *account = (char *)user_data; - if (*abort_del_user) + if (!account) return; ret = shm_lookup_users_map(share, KSMBD_SHARE_ADMIN_USERS_MAP, - arg_account); + account); if (ret == 0) goto conflict; ret = shm_lookup_users_map(share, KSMBD_SHARE_WRITE_LIST_MAP, - arg_account); + account); if (ret == 0) goto conflict; ret = shm_lookup_users_map(share, KSMBD_SHARE_VALID_USERS_MAP, - arg_account); + account); if (ret == 0) goto conflict; - *abort_del_user = 0; return; conflict: pr_err("Share %s requires user %s to exist\n", - share->name, arg_account); - *abort_del_user = 1; + share->name, account); + account = NULL; } -int command_add_user(char *pwddb, char *account, char *password) +int user_add_cmd(char *db, char *account, char *password) { struct ksmbd_user *user; - char *pswd; - - arg_account = account; - arg_password = password; + char *pw; - user = usm_lookup_user(arg_account); + user = usm_lookup_user(account); if (user) { put_ksmbd_user(user); - pr_err("Account `%s' already exists\n", arg_account); + pr_err("Account `%s' already exists\n", account); return -EEXIST; } - pswd = get_hashed_b64_password(); - if (!pswd) { + pw = get_hashed_b64_password(password); + if (!pw) { pr_err("Out of memory\n"); return -EINVAL; } - /* pswd is already g_strdup-ed */ - if (usm_add_new_user(arg_account, pswd)) { + /* pw is already g_strdup-ed */ + if (usm_add_new_user(account, pw)) { pr_err("Could not add new account\n"); return -EINVAL; } - pr_info("User '%s' added\n", arg_account); - if (__opendb_file(pwddb)) + if (open_db(db, true)) return -EINVAL; for_each_ksmbd_user(write_user_cb, NULL); + + pr_info("User '%s' added\n", account); + close(conf_fd); return 0; } -int command_update_user(char *pwddb, char *account, char *password) +int user_update_cmd(char *db, char *account, char *password) { struct ksmbd_user *user; - char *pswd; - - arg_password = password; - arg_account = account; + char *pw; - user = usm_lookup_user(arg_account); + user = usm_lookup_user(account); if (!user) { - pr_err("Unknown account\n"); + pr_err("Unknown account \"%s\"\n", account); return -EINVAL; } - pswd = get_hashed_b64_password(); - if (!pswd) { + pw = get_hashed_b64_password(password); + if (!pw) { pr_err("Out of memory\n"); put_ksmbd_user(user); return -EINVAL; } - if (usm_update_user_password(user, pswd)) { + if (usm_update_user_password(user, pw)) { pr_err("Out of memory\n"); put_ksmbd_user(user); return -ENOMEM; @@ -359,9 +353,9 @@ int command_update_user(char *pwddb, char *account, char *password) pr_info("User '%s' updated\n", account); put_ksmbd_user(user); - free(pswd); + free(pw); - if (__opendb_file(pwddb)) + if (open_db(db, true)) return -EINVAL; for_each_ksmbd_user(write_user_cb, NULL); @@ -369,28 +363,47 @@ int command_update_user(char *pwddb, char *account, char *password) return 0; } -int command_del_user(char *pwddb, char *account) +int user_delete_cmd(char *db, char *account) { - int abort_del_user = 0; + char *abort_del_user = strdup(account); - arg_account = account; - if (!cp_key_cmp(global_conf.guest_account, arg_account)) { + if (!cp_key_cmp(global_conf.guest_account, account)) { pr_err("User %s is a global guest account. Abort deletion.\n", - arg_account); + account); return -EINVAL; } - for_each_ksmbd_share(lookup_can_del_user, &abort_del_user); + for_each_ksmbd_share(lookup_can_del_user, abort_del_user); - if (abort_del_user) { + if (!abort_del_user) { pr_err("Aborting user deletion\n"); return -EINVAL; } - if (__opendb_file(pwddb)) + if (open_db(db, true)) + return -EINVAL; + + for_each_ksmbd_user(write_remove_user_cb, account); + close(conf_fd); + return 0; +} + +static void list_users_cb(gpointer key, gpointer value, gpointer data) +{ + struct ksmbd_user *user = (struct ksmbd_user *)value; + + pr_out("%s\n", user->name); +} + +int user_list_cmd(char *db) +{ + if (open_db(db, false)) return -EINVAL; - for_each_ksmbd_user(write_remove_user_cb, NULL); + pr_out("Users in %s:\n", db); + for_each_ksmbd_user(list_users_cb, NULL); + pr_out("\n"); close(conf_fd); + return 0; } diff --git a/user/user_admin.h b/user/user_admin.h index 9ff839e846bd..2dfbaa00b6b0 100644 --- a/user/user_admin.h +++ b/user/user_admin.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2018 Samsung Electronics Co., Ltd. + * Copyright (C) 2021 SUSE LLC * * linux-cifsd-devel@lists.sourceforge.net */ @@ -8,8 +9,36 @@ #ifndef __KSMBD_USER_ADMIN_H__ #define __KSMBD_USER_ADMIN_H__ -int command_add_user(char *pwddb, char *account, char *password); -int command_update_user(char *pwddb, char *account, char *password); -int command_del_user(char *pwddb, char *account); +int user_add_cmd(char *db, char *account, char *password); +int user_delete_cmd(char *db, char *account); +int user_update_cmd(char *db, char *account, char *password); +int user_list_cmd(char *db); + +typedef enum { + KSMBD_CMD_USER_NONE = 0, + KSMBD_CMD_USER_ADD, + KSMBD_CMD_USER_DELETE, + KSMBD_CMD_USER_UPDATE, + KSMBD_CMD_USER_LIST, + KSMBD_CMD_USER_MAX +} ksmbd_user_cmd; + +/* List of supported subcommands */ +static const char *ksmbd_user_cmds_str[] = { + "none", + "add", + "delete", + "update", + "list", +}; + +static struct option user_opts[] = { + { "password", required_argument, NULL, 'p' }, + { "database", required_argument, NULL, 'd' }, + { 0, 0, 0, 0 }, +}; + +void user_usage(ksmbd_user_cmd cmd); +int user_cmd(int argc, char *argv[]); #endif /* __KSMBD_USER_ADMIN_H__ */
Create user command in preparation for binary unification. Rename some variables to make them more relatable to user properties and management. Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de> --- daemon/daemon.c | 12 +- daemon/ipc.c | 6 +- include/config_parser.h | 2 +- include/ksmbdtools.h | 7 +- lib/config_parser.c | 4 +- user/Makefile.am | 2 +- user/adduser.c | 180 ----------------------------- user/user.c | 238 ++++++++++++++++++++++++++++++++++++++ user/user_admin.c | 247 +++++++++++++++++++++------------------- user/user_admin.h | 35 +++++- 10 files changed, 417 insertions(+), 316 deletions(-) delete mode 100644 user/adduser.c create mode 100644 user/user.c