linux-cifs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/9] Unify all programs into a single binary "ksmbdctl"
@ 2022-03-07  1:33 Enzo Matsumiya
  2022-03-07  1:33 ` [PATCH 1/9] ksmbd-tools: rename dirs to reflect new commands Enzo Matsumiya
                   ` (9 more replies)
  0 siblings, 10 replies; 13+ messages in thread
From: Enzo Matsumiya @ 2022-03-07  1:33 UTC (permalink / raw)
  To: linux-cifs, linkinjeon
  Cc: senozhatsky, sergey.senozhatsky, hyc.lee, smfrench, Enzo Matsumiya

Hello,

This commit unifies all existing programs
(ksmbd.{adduser,addshare,control,mountd}) into a single ksmbdctl binary.

The intention is to make it more like other modern tools (e.g. git,
nvme, virsh, etc) which have more clear user interface, readable
commands, and also makes it easier to script.

Example commands:
  # ksmbdctl share add myshare -o "guest ok=yes, writable=yes, path=/mnt/data"
  # ksmbdctl user add myuser
  # ksmbdctl user add -i $HOME/mysmb.conf anotheruser
  # ksmbdctl daemon start

Besides adding a new "share list" command, any previously working
functionality shouldn't be affected.

Basic testing was done manually.

TODO:
- run more complex tests in more complex environments
- implement unit tests (for each command and subcommand)
- create an abstract command interface, to make it easier to add/modify
  commands

Enzo Matsumiya (9):
  ksmbd-tools: rename dirs to reflect new commands
  ksmbd-tools: move control functions to daemon
  ksmbd-tools: use quotes for local includes
  share: introduce share_cmd
  user: introduce user_cmd
  daemon: introduce daemon_cmd
  daemon/rpc_samr: drop unused function rpc_samr_remove_domain_entry()
  Unify all programs into a single binary "ksmbdctl"
  README: change to markdown, updates for ksmbdctl

 Makefile.am                        |  14 +-
 README                             | 100 -------
 README.md                          |  57 ++--
 addshare/addshare.c                | 172 -------------
 addshare/share_admin.h             |  15 --
 adduser/adduser.c                  | 180 -------------
 adduser/user_admin.h               |  15 --
 configure.ac                       |   7 +-
 control/Makefile.am                |   7 -
 control/control.c                  | 128 ---------
 {mountd => daemon}/Makefile.am     |   2 +-
 mountd/mountd.c => daemon/daemon.c | 401 +++++++++++++++++++++--------
 daemon/daemon.h                    |  55 ++++
 {mountd => daemon}/ipc.c           |  27 +-
 {mountd => daemon}/rpc.c           |  21 +-
 {mountd => daemon}/rpc_lsarpc.c    |  13 +-
 {mountd => daemon}/rpc_samr.c      |  22 +-
 {mountd => daemon}/rpc_srvsvc.c    |  11 +-
 {mountd => daemon}/rpc_wkssvc.c    |  10 +-
 {mountd => daemon}/smbacl.c        |   4 +-
 {mountd => daemon}/worker.c        |  32 +--
 include/config_parser.h            |   2 +-
 include/ksmbdtools.h               |  24 +-
 ksmbdctl.c                         | 182 +++++++++++++
 lib/config_parser.c                |  15 +-
 lib/ksmbdtools.c                   |  26 +-
 lib/management/spnego.c            |   6 +-
 lib/management/spnego_krb5.c       |   4 +-
 {addshare => share}/Makefile.am    |   2 +-
 share/share.c                      | 227 ++++++++++++++++
 {addshare => share}/share_admin.c  |  97 +++++--
 share/share_admin.h                |  44 ++++
 {adduser => user}/Makefile.am      |   2 +-
 {adduser => user}/md4_hash.c       |   2 +-
 {adduser => user}/md4_hash.h       |   0
 user/user.c                        | 238 +++++++++++++++++
 {adduser => user}/user_admin.c     | 263 ++++++++++---------
 user/user_admin.h                  |  44 ++++
 38 files changed, 1458 insertions(+), 1013 deletions(-)
 delete mode 100644 README
 delete mode 100644 addshare/addshare.c
 delete mode 100644 addshare/share_admin.h
 delete mode 100644 adduser/adduser.c
 delete mode 100644 adduser/user_admin.h
 delete mode 100644 control/Makefile.am
 delete mode 100644 control/control.c
 rename {mountd => daemon}/Makefile.am (95%)
 rename mountd/mountd.c => daemon/daemon.c (55%)
 create mode 100644 daemon/daemon.h
 rename {mountd => daemon}/ipc.c (95%)
 rename {mountd => daemon}/rpc.c (98%)
 rename {mountd => daemon}/rpc_lsarpc.c (98%)
 rename {mountd => daemon}/rpc_samr.c (98%)
 rename {mountd => daemon}/rpc_srvsvc.c (98%)
 rename {mountd => daemon}/rpc_wkssvc.c (97%)
 rename {mountd => daemon}/smbacl.c (99%)
 rename {mountd => daemon}/worker.c (95%)
 create mode 100644 ksmbdctl.c
 rename {addshare => share}/Makefile.am (74%)
 create mode 100644 share/share.c
 rename {addshare => share}/share_admin.c (68%)
 create mode 100644 share/share_admin.h
 rename {adduser => user}/Makefile.am (69%)
 rename {adduser => user}/md4_hash.c (99%)
 rename {adduser => user}/md4_hash.h (100%)
 create mode 100644 user/user.c
 rename {adduser => user}/user_admin.c (52%)
 create mode 100644 user/user_admin.h

-- 
2.34.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 1/9] ksmbd-tools: rename dirs to reflect new commands
  2022-03-07  1:33 [PATCH 0/9] Unify all programs into a single binary "ksmbdctl" Enzo Matsumiya
@ 2022-03-07  1:33 ` Enzo Matsumiya
  2022-03-07  1:33 ` [PATCH 2/9] ksmbd-tools: move control functions to daemon Enzo Matsumiya
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Enzo Matsumiya @ 2022-03-07  1:33 UTC (permalink / raw)
  To: linux-cifs, linkinjeon
  Cc: senozhatsky, sergey.senozhatsky, hyc.lee, smfrench, Enzo Matsumiya

Rename directories to reflect command names, in preparation for binary
unification.

Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
---
 Makefile.am                        | 2 +-
 configure.ac                       | 6 +++---
 {mountd => daemon}/Makefile.am     | 2 +-
 mountd/mountd.c => daemon/daemon.c | 0
 {mountd => daemon}/ipc.c           | 0
 {mountd => daemon}/rpc.c           | 0
 {mountd => daemon}/rpc_lsarpc.c    | 0
 {mountd => daemon}/rpc_samr.c      | 0
 {mountd => daemon}/rpc_srvsvc.c    | 0
 {mountd => daemon}/rpc_wkssvc.c    | 0
 {mountd => daemon}/smbacl.c        | 0
 {mountd => daemon}/worker.c        | 0
 {addshare => share}/Makefile.am    | 0
 {addshare => share}/addshare.c     | 0
 {addshare => share}/share_admin.c  | 0
 {addshare => share}/share_admin.h  | 0
 {adduser => user}/Makefile.am      | 0
 {adduser => user}/adduser.c        | 0
 {adduser => user}/md4_hash.c       | 0
 {adduser => user}/md4_hash.h       | 0
 {adduser => user}/user_admin.c     | 0
 {adduser => user}/user_admin.h     | 0
 22 files changed, 5 insertions(+), 5 deletions(-)
 rename {mountd => daemon}/Makefile.am (95%)
 rename mountd/mountd.c => daemon/daemon.c (100%)
 rename {mountd => daemon}/ipc.c (100%)
 rename {mountd => daemon}/rpc.c (100%)
 rename {mountd => daemon}/rpc_lsarpc.c (100%)
 rename {mountd => daemon}/rpc_samr.c (100%)
 rename {mountd => daemon}/rpc_srvsvc.c (100%)
 rename {mountd => daemon}/rpc_wkssvc.c (100%)
 rename {mountd => daemon}/smbacl.c (100%)
 rename {mountd => daemon}/worker.c (100%)
 rename {addshare => share}/Makefile.am (100%)
 rename {addshare => share}/addshare.c (100%)
 rename {addshare => share}/share_admin.c (100%)
 rename {addshare => share}/share_admin.h (100%)
 rename {adduser => user}/Makefile.am (100%)
 rename {adduser => user}/adduser.c (100%)
 rename {adduser => user}/md4_hash.c (100%)
 rename {adduser => user}/md4_hash.h (100%)
 rename {adduser => user}/user_admin.c (100%)
 rename {adduser => user}/user_admin.h (100%)

diff --git a/Makefile.am b/Makefile.am
index 00a6148ff29d..e3ee928691bf 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,7 +2,7 @@
 
 ACLOCAL_AMFLAGS = -I m4
 
-SUBDIRS = lib mountd adduser addshare control
+SUBDIRS = lib daemon user share control
 
 # other stuff
 EXTRA_DIST =			\
diff --git a/configure.ac b/configure.ac
index 6aceade6ed01..1f107805325f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -62,9 +62,9 @@ AM_CONDITIONAL(HAVE_LIBKRB5, [test "$enable_krb5" != "no"])
 AC_CONFIG_FILES([
 	Makefile
 	lib/Makefile
-	mountd/Makefile
-	adduser/Makefile
-	addshare/Makefile
+	daemon/Makefile
+	user/Makefile
+	share/Makefile
 	control/Makefile
 ])
 
diff --git a/mountd/Makefile.am b/daemon/Makefile.am
similarity index 95%
rename from mountd/Makefile.am
rename to daemon/Makefile.am
index 4719170f2d05..6249a098025d 100644
--- a/mountd/Makefile.am
+++ b/daemon/Makefile.am
@@ -4,5 +4,5 @@ ksmbd_mountd_LDADD = $(top_builddir)/lib/libksmbdtools.a
 
 sbin_PROGRAMS = ksmbd.mountd
 
-ksmbd_mountd_SOURCES = worker.c ipc.c rpc.c rpc_srvsvc.c rpc_wkssvc.c mountd.c \
+ksmbd_mountd_SOURCES = worker.c ipc.c rpc.c rpc_srvsvc.c rpc_wkssvc.c daemon.c \
 		       smbacl.c rpc_samr.c rpc_lsarpc.c
diff --git a/mountd/mountd.c b/daemon/daemon.c
similarity index 100%
rename from mountd/mountd.c
rename to daemon/daemon.c
diff --git a/mountd/ipc.c b/daemon/ipc.c
similarity index 100%
rename from mountd/ipc.c
rename to daemon/ipc.c
diff --git a/mountd/rpc.c b/daemon/rpc.c
similarity index 100%
rename from mountd/rpc.c
rename to daemon/rpc.c
diff --git a/mountd/rpc_lsarpc.c b/daemon/rpc_lsarpc.c
similarity index 100%
rename from mountd/rpc_lsarpc.c
rename to daemon/rpc_lsarpc.c
diff --git a/mountd/rpc_samr.c b/daemon/rpc_samr.c
similarity index 100%
rename from mountd/rpc_samr.c
rename to daemon/rpc_samr.c
diff --git a/mountd/rpc_srvsvc.c b/daemon/rpc_srvsvc.c
similarity index 100%
rename from mountd/rpc_srvsvc.c
rename to daemon/rpc_srvsvc.c
diff --git a/mountd/rpc_wkssvc.c b/daemon/rpc_wkssvc.c
similarity index 100%
rename from mountd/rpc_wkssvc.c
rename to daemon/rpc_wkssvc.c
diff --git a/mountd/smbacl.c b/daemon/smbacl.c
similarity index 100%
rename from mountd/smbacl.c
rename to daemon/smbacl.c
diff --git a/mountd/worker.c b/daemon/worker.c
similarity index 100%
rename from mountd/worker.c
rename to daemon/worker.c
diff --git a/addshare/Makefile.am b/share/Makefile.am
similarity index 100%
rename from addshare/Makefile.am
rename to share/Makefile.am
diff --git a/addshare/addshare.c b/share/addshare.c
similarity index 100%
rename from addshare/addshare.c
rename to share/addshare.c
diff --git a/addshare/share_admin.c b/share/share_admin.c
similarity index 100%
rename from addshare/share_admin.c
rename to share/share_admin.c
diff --git a/addshare/share_admin.h b/share/share_admin.h
similarity index 100%
rename from addshare/share_admin.h
rename to share/share_admin.h
diff --git a/adduser/Makefile.am b/user/Makefile.am
similarity index 100%
rename from adduser/Makefile.am
rename to user/Makefile.am
diff --git a/adduser/adduser.c b/user/adduser.c
similarity index 100%
rename from adduser/adduser.c
rename to user/adduser.c
diff --git a/adduser/md4_hash.c b/user/md4_hash.c
similarity index 100%
rename from adduser/md4_hash.c
rename to user/md4_hash.c
diff --git a/adduser/md4_hash.h b/user/md4_hash.h
similarity index 100%
rename from adduser/md4_hash.h
rename to user/md4_hash.h
diff --git a/adduser/user_admin.c b/user/user_admin.c
similarity index 100%
rename from adduser/user_admin.c
rename to user/user_admin.c
diff --git a/adduser/user_admin.h b/user/user_admin.h
similarity index 100%
rename from adduser/user_admin.h
rename to user/user_admin.h
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 2/9] ksmbd-tools: move control functions to daemon
  2022-03-07  1:33 [PATCH 0/9] Unify all programs into a single binary "ksmbdctl" Enzo Matsumiya
  2022-03-07  1:33 ` [PATCH 1/9] ksmbd-tools: rename dirs to reflect new commands Enzo Matsumiya
@ 2022-03-07  1:33 ` Enzo Matsumiya
  2022-03-07  1:33 ` [PATCH 3/9] ksmbd-tools: use quotes for local includes Enzo Matsumiya
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Enzo Matsumiya @ 2022-03-07  1:33 UTC (permalink / raw)
  To: linux-cifs, linkinjeon
  Cc: senozhatsky, sergey.senozhatsky, hyc.lee, smfrench, Enzo Matsumiya

Move the control functionality to the daemon command.

This commit builds, but doesn't work since the commands will be
implemented in a next patch from this series.

Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
---
 Makefile.am          |   2 +-
 configure.ac         |   1 -
 control/Makefile.am  |   7 ---
 control/control.c    | 128 -------------------------------------------
 daemon/daemon.c      |  85 +++++++++++++++++++++++++++-
 daemon/daemon.h      |  29 ++++++++++
 include/ksmbdtools.h |   1 +
 lib/ksmbdtools.c     |  24 ++++++++
 8 files changed, 139 insertions(+), 138 deletions(-)
 delete mode 100644 control/Makefile.am
 delete mode 100644 control/control.c
 create mode 100644 daemon/daemon.h

diff --git a/Makefile.am b/Makefile.am
index e3ee928691bf..b4e205895825 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,7 +2,7 @@
 
 ACLOCAL_AMFLAGS = -I m4
 
-SUBDIRS = lib daemon user share control
+SUBDIRS = lib daemon user share
 
 # other stuff
 EXTRA_DIST =			\
diff --git a/configure.ac b/configure.ac
index 1f107805325f..d7ec538cbbf0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -65,7 +65,6 @@ AC_CONFIG_FILES([
 	daemon/Makefile
 	user/Makefile
 	share/Makefile
-	control/Makefile
 ])
 
 AC_OUTPUT
diff --git a/control/Makefile.am b/control/Makefile.am
deleted file mode 100644
index 0b3559ab60ed..000000000000
--- a/control/Makefile.am
+++ /dev/null
@@ -1,7 +0,0 @@
-AM_CFLAGS = -I$(top_srcdir)/include $(GLIB_CFLAGS) $(LIBNL_CFLAGS) -fno-common
-LIBS = $(GLIB_LIBS)
-ksmbd_control_LDADD = $(top_builddir)/lib/libksmbdtools.a
-
-sbin_PROGRAMS = ksmbd.control
-
-ksmbd_control_SOURCES = control.c
diff --git a/control/control.c b/control/control.c
deleted file mode 100644
index 780a48ab9259..000000000000
--- a/control/control.c
+++ /dev/null
@@ -1,128 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *   Copyright (C) 2020 Samsung Electronics Co., Ltd.
- *
- *   linux-cifsd-devel@lists.sourceforge.net
- */
-
-#include <getopt.h>
-#include <fcntl.h>
-#include <errno.h>
-
-#include "ksmbdtools.h"
-#include "version.h"
-
-static void usage(void)
-{
-	fprintf(stderr, "Usage: ksmbd.control\n");
-	fprintf(stderr, "\t-s | --shutdown\n");
-	fprintf(stderr, "\t-d | --debug=all or [smb, auth, etc...]\n");
-	fprintf(stderr, "\t-c | --ksmbd-version\n");
-	fprintf(stderr, "\t-V | --version\n");
-
-	exit(EXIT_FAILURE);
-}
-
-static void show_version(void)
-{
-	printf("ksmbd-tools version : %s\n", KSMBD_TOOLS_VERSION);
-	exit(EXIT_FAILURE);
-}
-
-static int ksmbd_control_shutdown(void)
-{
-	int fd, ret;
-
-	terminate_ksmbd_daemon();
-
-	fd = open("/sys/class/ksmbd-control/kill_server", O_WRONLY);
-	if (fd < 0) {
-		pr_err("open failed: %d\n", errno);
-		return EXIT_FAILURE;
-	}
-
-	ret = write(fd, "hard", 4);
-	close(fd);
-	return ret != -1 ? EXIT_SUCCESS : EXIT_FAILURE;
-}
-
-static int ksmbd_control_show_version(void)
-{
-	int fd, ret;
-	char ver[255] = {0};
-
-	fd = open("/sys/module/ksmbd/version", O_RDONLY);
-	if (fd < 0) {
-		pr_err("open failed: %d\n", errno);
-		return EXIT_FAILURE;
-	}
-
-	ret = read(fd, ver, 255);
-	close(fd);
-	if (ret != -1)
-		pr_info("ksmbd version : %s\n", ver);
-	return ret != -1 ? EXIT_SUCCESS : EXIT_FAILURE;
-}
-
-static int ksmbd_control_debug(char *comp)
-{
-	int fd, ret;
-	char buf[255] = {0};
-
-	fd = open("/sys/class/ksmbd-control/debug", O_RDWR);
-	if (fd < 0) {
-		pr_err("open failed: %d\n", errno);
-		return EXIT_FAILURE;
-	}
-
-	ret = write(fd, comp, strlen(comp));
-	if (ret < 0)
-		goto out;
-	ret = read(fd, buf, 255);
-	if (ret < 0)
-		goto out;
-
-	pr_info("%s\n", buf);
-out:
-	close(fd);
-	return ret != -1 ? EXIT_SUCCESS : EXIT_FAILURE;
-}
-
-int main(int argc, char *argv[])
-{
-	int ret = EXIT_FAILURE;
-	int c;
-
-	set_logger_app_name("ksmbd.control");
-
-	if (getuid() != 0) {
-		pr_err("Please try it as root.\n");
-		return ret;
-	}
-
-	opterr = 0;
-	while ((c = getopt(argc, argv, "sd:cVh")) != EOF)
-		switch (c) {
-		case 's':
-			ret = ksmbd_control_shutdown();
-			break;
-		case 'd':
-			ret = ksmbd_control_debug(optarg);
-			break;
-		case 'c':
-			ret = ksmbd_control_show_version();
-			break;
-		case 'V':
-			show_version();
-			break;
-		case '?':
-		case 'h':
-		default:
-			usage();
-	}
-
-	if (argc < 2)
-		usage();
-
-	return ret;
-}
diff --git a/daemon/daemon.c b/daemon/daemon.c
index a3a683222a92..946f500bc977 100644
--- a/daemon/daemon.c
+++ b/daemon/daemon.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
  */
@@ -13,6 +14,7 @@
 
 #include <stdlib.h>
 #include <stdio.h>
+#include <stdbool.h>
 #include <unistd.h>
 #include <getopt.h>
 #include <fcntl.h>
@@ -24,6 +26,7 @@
 #include "ipc.h"
 #include "rpc.h"
 #include "worker.h"
+#include "daemon.h"
 #include "config_parser.h"
 #include "management/user.h"
 #include "management/share.h"
@@ -555,12 +558,92 @@ static struct option opts[] = {
 	{NULL,		0,			NULL,	 0  }
 };
 
+int daemon_shutdown_cmd(void)
+{
+	int fd, ret;
+
+	if (get_running_pid() == -ENOENT) {
+		pr_info("Server is not running.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	terminate_ksmbd_daemon();
+
+	fd = open(KSMBD_SYSFS_KILL_SERVER, O_WRONLY);
+	if (fd < 0) {
+		pr_debug("open failed (%d): %s\n", errno, strerr(errno));
+		return fd;
+	}
+
+	ret = write(fd, "hard", 4);
+	close(fd);
+	return ret;
+}
+
+int daemon_debug_cmd(char *debug_type)
+{
+	int i, fd, ret;
+	bool valid = false;
+	char buf[255] = { 0 };
+
+	for (i = 0; i < ARRAY_SIZE(debug_type_strings); i++) {
+		if (!strcmp(debug_type, debug_type_strings[i])) {
+			valid = true;
+			break;
+		}
+	}
+
+	if (!valid)
+		return -EINVAL;
+
+	ret = fd = open(KSMBD_SYSFS_DEBUG, O_RDWR);
+	if (fd < 0)
+		goto err_open;
+
+	ret = write(fd, debug_type, strlen(debug_type));
+	if (ret < 0)
+		goto err;
+
+	ret = read(fd, buf, 255);
+	if (ret < 0)
+		goto err;
+
+	pr_info("debug: %s\n", buf);
+err:
+	close(fd);
+err_open:
+	if (ret == -EBADF)
+		pr_debug("Can't open %s. Is ksmbd kernel module loaded?\n");
+	return ret;
+}
+
+int daemon_version_cmd(void)
+{
+	int fd, ret;
+	char version[255] = { 0 };
+
+	ret = fd = open(KSMBD_SYSFS_VERSION, O_RDONLY);
+	if (fd < 0)
+		goto err;
+
+	ret = read(fd, version, 255);
+	close(fd);
+
+err:
+	if (ret < 0)
+		pr_err("%s. Is kernel module loaded?\n", strerr(errno));
+	else
+		pr_info("ksmbd module version: %s\n", version);
+
+	return ret;
+}
+
 int main(int argc, char *argv[])
 {
 	int systemd_service = 0;
 	int c;
 
-	set_logger_app_name("ksmbd.mountd");
+	set_logger_app_name("ksmbd.daemon");
 	memset(&global_conf, 0x00, sizeof(struct smbconf_global));
 	global_conf.pwddb = PATH_PWDDB;
 	global_conf.smbconf = PATH_SMBCONF;
diff --git a/daemon/daemon.h b/daemon/daemon.h
new file mode 100644
index 000000000000..ca064b2b732d
--- /dev/null
+++ b/daemon/daemon.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ *   Copyright (C) 2021 SUSE LLC
+ *
+ *   linux-cifsd-devel@lists.sourceforge.net
+ */
+
+#ifndef __DAEMON_H__
+#define __DAEMON_H__
+
+#define KSMBD_SYSFS_KILL_SERVER "/sys/class/ksmbd-control/kill_server"
+#define KSMBD_SYSFS_DEBUG	"/sys/class/ksmbd-control/debug"
+#define KSMBD_SYSFS_VERSION	"/sys/module/ksmbd/version"
+
+static const char * const debug_type_strings[] = {
+	"all", "smb", "auth", "vfs", "oplock", "ipc", "conn", "rdma"
+};
+
+static struct option daemon_opts[] = {
+	{ "port", required_argument, NULL, 'p' },
+	{ "config", required_argument, NULL, 'c' },
+	{ "usersdb", required_argument, NULL, 'u' },
+	{ "nodetach", no_argument, NULL, 'n' },
+	{ "systemd", no_argument, NULL, 's' },
+	{ "help", no_argument, NULL, 'h' },
+	{ 0, 0, 0, 0 },
+};
+
+#endif /* __DAEMON_H__ */
diff --git a/include/ksmbdtools.h b/include/ksmbdtools.h
index c51673e0253f..170ce23ead2c 100644
--- a/include/ksmbdtools.h
+++ b/include/ksmbdtools.h
@@ -168,6 +168,7 @@ enum charset_idx {
 
 extern char *ksmbd_conv_charsets[KSMBD_CHARSET_MAX + 1];
 
+int get_running_pid(void);
 void notify_ksmbd_daemon(void);
 void terminate_ksmbd_daemon(void);
 int test_file_access(char *conf);
diff --git a/lib/ksmbdtools.c b/lib/ksmbdtools.c
index 91d82946f6d6..b636f34af98e 100644
--- a/lib/ksmbdtools.c
+++ b/lib/ksmbdtools.c
@@ -255,6 +255,30 @@ void terminate_ksmbd_daemon(void)
 	send_signal_to_ksmbd_daemon(SIGTERM);
 }
 
+int get_running_pid(void)
+{
+	char daemon_pid[10] = { 0 };
+	pid_t pid = 0;
+	int fd;
+
+	fd = open(KSMBD_LOCK_FILE, O_RDONLY);
+	if (fd < 0) {
+		pr_info("Can't open lock file %s: %s\n", KSMBD_LOCK_FILE, strerr(errno));
+		return -ENOENT;
+	}
+
+	if (read(fd, &daemon_pid, sizeof(daemon_pid)) == -1) {
+		pr_err("Unable to read lock file: %s\n", strerr(errno));
+		close(fd);
+		return -EINVAL;
+	}
+
+	close(fd);
+	pid = strtol(daemon_pid, NULL, 10);
+
+	return pid;
+}
+
 int test_file_access(char *conf)
 {
 	int fd = open(conf, O_RDWR | O_CREAT, S_IRWXU | S_IRGRP);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 3/9] ksmbd-tools: use quotes for local includes
  2022-03-07  1:33 [PATCH 0/9] Unify all programs into a single binary "ksmbdctl" Enzo Matsumiya
  2022-03-07  1:33 ` [PATCH 1/9] ksmbd-tools: rename dirs to reflect new commands Enzo Matsumiya
  2022-03-07  1:33 ` [PATCH 2/9] ksmbd-tools: move control functions to daemon Enzo Matsumiya
@ 2022-03-07  1:33 ` Enzo Matsumiya
  2022-03-07  1:33 ` [PATCH 4/9] share: introduce share_cmd Enzo Matsumiya
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Enzo Matsumiya @ 2022-03-07  1:33 UTC (permalink / raw)
  To: linux-cifs, linkinjeon
  Cc: senozhatsky, sergey.senozhatsky, hyc.lee, smfrench, Enzo Matsumiya

Cosmetic only, but better practice.

Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
---
 daemon/ipc.c                 | 16 ++++++++--------
 daemon/rpc.c                 | 17 +++++++++--------
 daemon/rpc_lsarpc.c          | 13 +++++++------
 daemon/rpc_samr.c            | 13 +++++++------
 daemon/rpc_srvsvc.c          | 11 ++++++-----
 daemon/rpc_wkssvc.c          | 10 +++++-----
 daemon/smbacl.c              |  4 ++--
 daemon/worker.c              | 19 ++++++++++---------
 lib/config_parser.c          | 11 ++++++-----
 lib/ksmbdtools.c             |  2 +-
 lib/management/spnego.c      |  6 +++---
 lib/management/spnego_krb5.c |  4 ++--
 share/share_admin.c          | 12 +++++-------
 user/md4_hash.c              |  2 +-
 user/user_admin.c            | 16 +++++++---------
 15 files changed, 79 insertions(+), 77 deletions(-)

diff --git a/daemon/ipc.c b/daemon/ipc.c
index eded431e8112..c46cbc174175 100644
--- a/daemon/ipc.c
+++ b/daemon/ipc.c
@@ -15,14 +15,14 @@
 #include <linux/genetlink.h>
 #include <netlink/genl/mngt.h>
 
-#include <linux/ksmbd_server.h>
-
-#include <ksmbdtools.h>
-#include <ipc.h>
-#include <worker.h>
-#include <config_parser.h>
-#include <management/user.h>
-#include <management/share.h>
+#include "linux/ksmbd_server.h"
+
+#include "ksmbdtools.h"
+#include "ipc.h"
+#include "worker.h"
+#include "config_parser.h"
+#include "management/user.h"
+#include "management/share.h"
 
 static struct nl_sock *sk;
 
diff --git a/daemon/rpc.c b/daemon/rpc.c
index 2361634f1a55..ab2a7c6dfebe 100644
--- a/daemon/rpc.c
+++ b/daemon/rpc.c
@@ -9,14 +9,15 @@
 #include <endian.h>
 #include <glib.h>
 #include <errno.h>
-#include <linux/ksmbd_server.h>
-
-#include <rpc.h>
-#include <rpc_srvsvc.h>
-#include <rpc_wkssvc.h>
-#include <rpc_samr.h>
-#include <rpc_lsarpc.h>
-#include <ksmbdtools.h>
+
+#include "linux/ksmbd_server.h"
+
+#include "rpc.h"
+#include "rpc_srvsvc.h"
+#include "rpc_wkssvc.h"
+#include "rpc_samr.h"
+#include "rpc_lsarpc.h"
+#include "ksmbdtools.h"
 
 static GHashTable	*pipes_table;
 static GRWLock		pipes_table_lock;
diff --git a/daemon/rpc_lsarpc.c b/daemon/rpc_lsarpc.c
index 5caf4d9ef3ac..23fc68c3810b 100644
--- a/daemon/rpc_lsarpc.c
+++ b/daemon/rpc_lsarpc.c
@@ -10,13 +10,14 @@
 #include <glib.h>
 #include <pwd.h>
 #include <errno.h>
-#include <linux/ksmbd_server.h>
 
-#include <management/user.h>
-#include <rpc.h>
-#include <rpc_lsarpc.h>
-#include <smbacl.h>
-#include <ksmbdtools.h>
+#include "linux/ksmbd_server.h"
+
+#include "management/user.h"
+#include "rpc.h"
+#include "rpc_lsarpc.h"
+#include "smbacl.h"
+#include "ksmbdtools.h"
 
 #define LSARPC_OPNUM_DS_ROLE_GET_PRIMARY_DOMAIN_INFO	0
 #define LSARPC_OPNUM_OPEN_POLICY2			44
diff --git a/daemon/rpc_samr.c b/daemon/rpc_samr.c
index 95c607c101a3..396e38f58013 100644
--- a/daemon/rpc_samr.c
+++ b/daemon/rpc_samr.c
@@ -9,13 +9,14 @@
 #include <endian.h>
 #include <glib.h>
 #include <errno.h>
-#include <linux/ksmbd_server.h>
 
-#include <management/user.h>
-#include <rpc.h>
-#include <rpc_samr.h>
-#include <smbacl.h>
-#include <ksmbdtools.h>
+#include "linux/ksmbd_server.h"
+
+#include "management/user.h"
+#include "rpc.h"
+#include "rpc_samr.h"
+#include "smbacl.h"
+#include "ksmbdtools.h"
 
 #define SAMR_OPNUM_CONNECT5		64
 #define SAMR_OPNUM_ENUM_DOMAIN		6
diff --git a/daemon/rpc_srvsvc.c b/daemon/rpc_srvsvc.c
index f3b4d069031a..c3ec1c2bccd5 100644
--- a/daemon/rpc_srvsvc.c
+++ b/daemon/rpc_srvsvc.c
@@ -9,13 +9,14 @@
 #include <endian.h>
 #include <glib.h>
 #include <errno.h>
-#include <linux/ksmbd_server.h>
 
-#include <management/share.h>
+#include "linux/ksmbd_server.h"
+ 
+#include "management/share.h"
 
-#include <rpc.h>
-#include <rpc_srvsvc.h>
-#include <ksmbdtools.h>
+#include "rpc.h"
+#include "rpc_srvsvc.h"
+#include "ksmbdtools.h"
 
 #define SHARE_TYPE_TEMP			0x40000000
 #define SHARE_TYPE_HIDDEN		0x80000000
diff --git a/daemon/rpc_wkssvc.c b/daemon/rpc_wkssvc.c
index 32b7893eb2c6..a84f99b41888 100644
--- a/daemon/rpc_wkssvc.c
+++ b/daemon/rpc_wkssvc.c
@@ -9,13 +9,13 @@
 #include <endian.h>
 #include <glib.h>
 #include <errno.h>
-#include <linux/ksmbd_server.h>
 
-#include <management/share.h>
+#include "linux/ksmbd_server.h"
 
-#include <rpc.h>
-#include <rpc_wkssvc.h>
-#include <ksmbdtools.h>
+#include "management/share.h"
+#include "rpc.h"
+#include "rpc_wkssvc.h"
+#include "ksmbdtools.h"
 
 #define WKSSVC_NETWKSTA_GET_INFO	(0)
 
diff --git a/daemon/smbacl.c b/daemon/smbacl.c
index 66531c3bebea..a0ce2878fa18 100644
--- a/daemon/smbacl.c
+++ b/daemon/smbacl.c
@@ -6,8 +6,8 @@
  *   Author(s): Namjae Jeon (linkinjeon@kernel.org)
  */
 
-#include <smbacl.h>
-#include <ksmbdtools.h>
+#include "smbacl.h"
+#include "ksmbdtools.h"
 #include <glib.h>
 #include <glib/gprintf.h>
 
diff --git a/daemon/worker.c b/daemon/worker.c
index 70f2655b36c3..0ddd88cea12c 100644
--- a/daemon/worker.c
+++ b/daemon/worker.c
@@ -7,17 +7,18 @@
 #include <memory.h>
 #include <glib.h>
 #include <errno.h>
-#include <linux/ksmbd_server.h>
 
-#include <ksmbdtools.h>
-#include <worker.h>
-#include <ipc.h>
-#include <rpc.h>
+#include "linux/ksmbd_server.h"
 
-#include <management/user.h>
-#include <management/share.h>
-#include <management/tree_conn.h>
-#include <management/spnego.h>
+#include "ksmbdtools.h"
+#include "worker.h"
+#include "ipc.h"
+#include "rpc.h"
+
+#include "management/user.h"
+#include "management/share.h"
+#include "management/tree_conn.h"
+#include "management/spnego.h"
 
 #define MAX_WORKER_THREADS	4
 static GThreadPool *pool;
diff --git a/lib/config_parser.c b/lib/config_parser.c
index aa1dbf2a403e..20e27c3ab8ec 100644
--- a/lib/config_parser.c
+++ b/lib/config_parser.c
@@ -12,12 +12,13 @@
 #include <sys/types.h>
 #include <unistd.h>
 #include <fcntl.h>
-#include <linux/ksmbd_server.h>
 
-#include <config_parser.h>
-#include <ksmbdtools.h>
-#include <management/user.h>
-#include <management/share.h>
+#include "linux/ksmbd_server.h"
+
+#include "config_parser.h"
+#include "ksmbdtools.h"
+#include "management/user.h"
+#include "management/share.h"
 
 struct smbconf_global global_conf;
 struct smbconf_parser parser;
diff --git a/lib/ksmbdtools.c b/lib/ksmbdtools.c
index b636f34af98e..126b20c6a56a 100644
--- a/lib/ksmbdtools.c
+++ b/lib/ksmbdtools.c
@@ -13,7 +13,7 @@
 #include <fcntl.h>
 
 #include <stdio.h>
-#include <ksmbdtools.h>
+#include "ksmbdtools.h"
 
 static const char *app_name = "unknown";
 static int log_open;
diff --git a/lib/management/spnego.c b/lib/management/spnego.c
index 473caf66e036..685d88beebc3 100644
--- a/lib/management/spnego.c
+++ b/lib/management/spnego.c
@@ -19,9 +19,9 @@
 #include <stdint.h>
 #include <stdbool.h>
 
-#include <linux/ksmbd_server.h>
-#include <management/spnego.h>
-#include <asn1.h>
+#include "linux/ksmbd_server.h"
+#include "management/spnego.h"
+#include "asn1.h"
 #include "spnego_mech.h"
 
 static struct spnego_mech_ctx mech_ctxs[SPNEGO_MAX_MECHS];
diff --git a/lib/management/spnego_krb5.c b/lib/management/spnego_krb5.c
index 4bf7585bfb09..9e1516642145 100644
--- a/lib/management/spnego_krb5.c
+++ b/lib/management/spnego_krb5.c
@@ -15,8 +15,8 @@
 #include <netdb.h>
 #include <krb5.h>
 
-#include <management/spnego.h>
-#include <asn1.h>
+#include "management/spnego.h"
+#include "asn1.h"
 #include "spnego_mech.h"
 
 struct spnego_krb5_ctx {
diff --git a/share/share_admin.c b/share/share_admin.c
index 8365f872d620..0ff13d8017dd 100644
--- a/share/share_admin.c
+++ b/share/share_admin.c
@@ -13,13 +13,11 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 
-#include <config_parser.h>
-#include <ksmbdtools.h>
-
-#include <management/share.h>
-
-#include <linux/ksmbd_server.h>
-#include <share_admin.h>
+#include "config_parser.h"
+#include "ksmbdtools.h"
+#include "management/share.h"
+#include "linux/ksmbd_server.h"
+#include "share_admin.h"
 
 static int conf_fd = -1;
 static char wbuf[16384];
diff --git a/user/md4_hash.c b/user/md4_hash.c
index 1dd4f61ac82a..3ef0996557c8 100644
--- a/user/md4_hash.c
+++ b/user/md4_hash.c
@@ -19,8 +19,8 @@
 
 #include <stdlib.h>
 #include <memory.h>
-#include <md4_hash.h>
 #include <asm/byteorder.h>
+#include "md4_hash.h"
 
 #define u8 unsigned char
 #define u32 unsigned int
diff --git a/user/user_admin.c b/user/user_admin.c
index 4e8591517c48..95b05ea33f28 100644
--- a/user/user_admin.c
+++ b/user/user_admin.c
@@ -14,15 +14,13 @@
 #include <fcntl.h>
 #include <termios.h>
 
-#include <config_parser.h>
-#include <ksmbdtools.h>
-
-#include <md4_hash.h>
-#include <user_admin.h>
-#include <management/user.h>
-#include <management/share.h>
-
-#include <linux/ksmbd_server.h>
+#include "config_parser.h"
+#include "ksmbdtools.h"
+#include "md4_hash.h"
+#include "user_admin.h"
+#include "management/user.h"
+#include "management/share.h"
+#include "linux/ksmbd_server.h"
 
 #define MAX_NT_PWD_LEN 129
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 4/9] share: introduce share_cmd
  2022-03-07  1:33 [PATCH 0/9] Unify all programs into a single binary "ksmbdctl" Enzo Matsumiya
                   ` (2 preceding siblings ...)
  2022-03-07  1:33 ` [PATCH 3/9] ksmbd-tools: use quotes for local includes Enzo Matsumiya
@ 2022-03-07  1:33 ` Enzo Matsumiya
  2022-03-10  2:19   ` Namjae Jeon
  2022-03-07  1:33 ` [PATCH 5/9] user: introduce user_cmd Enzo Matsumiya
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 13+ messages in thread
From: Enzo Matsumiya @ 2022-03-07  1:33 UTC (permalink / raw)
  To: linux-cifs, linkinjeon
  Cc: senozhatsky, sergey.senozhatsky, hyc.lee, smfrench, Enzo Matsumiya

Create share command in preparation for binary unification.

Introduce a command to list available shares.

Makes open_smbconf() optionally truncate the file (for list command).

Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
---
 include/ksmbdtools.h |  16 ++-
 share/Makefile.am    |   2 +-
 share/addshare.c     | 172 --------------------------------
 share/share.c        | 227 +++++++++++++++++++++++++++++++++++++++++++
 share/share_admin.c  |  85 ++++++++++++----
 share/share_admin.h  |  35 ++++++-
 6 files changed, 335 insertions(+), 202 deletions(-)
 delete mode 100644 share/addshare.c
 create mode 100644 share/share.c

diff --git a/include/ksmbdtools.h b/include/ksmbdtools.h
index 170ce23ead2c..fccb88d8898a 100644
--- a/include/ksmbdtools.h
+++ b/include/ksmbdtools.h
@@ -101,12 +101,14 @@ extern int ksmbd_health_status;
 //---------------------------------------------------------------//
 #define LOGAPP		"[%s/%d]:"
 #define PRERR		LOGAPP" ERROR: "
+#define PRWARN		LOGAPP" WARN: "
 #define PRINF		LOGAPP" INFO: "
 #define PRDEBUG		LOGAPP" DEBUG: "
 
 #define PR_ERROR	0
-#define PR_INFO		1
-#define PR_DEBUG	2
+#define PR_WARN		1
+#define PR_INFO		2
+#define PR_DEBUG	3
 
 static int log_level = PR_INFO;
 
@@ -134,12 +136,16 @@ extern void pr_logger_init(int flags);
 					##__VA_ARGS__);			\
 	} while (0)
 
-#define pr_debug(f, ...)	\
+#define pr_debug(f, ...) \
 	pr_log(PR_DEBUG, PRDEBUG f, ##__VA_ARGS__)
-#define pr_info(f, ...)	\
+#define pr_info(f, ...) \
 	pr_log(PR_INFO, PRINF f, ##__VA_ARGS__)
-#define pr_err(f, ...)	\
+#define pr_warn(f, ...) \
+	pr_log(PR_WARN, PRWARN f, ##__VA_ARGS__)
+#define pr_err(f, ...) \
 	pr_log(PR_ERROR, PRERR f, ##__VA_ARGS__)
+#define pr_out(f, ...) \
+	fprintf(stderr, f, ##__VA_ARGS__)
 
 //---------------------------------------------------------------//
 
diff --git a/share/Makefile.am b/share/Makefile.am
index dafc985add5d..bea487edfeeb 100644
--- a/share/Makefile.am
+++ b/share/Makefile.am
@@ -4,4 +4,4 @@ ksmbd_addshare_LDADD = $(top_builddir)/lib/libksmbdtools.a
 
 sbin_PROGRAMS = ksmbd.addshare
 
-ksmbd_addshare_SOURCES = share_admin.c addshare.c share_admin.h
+ksmbd_addshare_SOURCES = share_admin.c share.c share_admin.h
diff --git a/share/addshare.c b/share/addshare.c
deleted file mode 100644
index 4ff94b18a641..000000000000
--- a/share/addshare.c
+++ /dev/null
@@ -1,172 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *   Copyright (C) 2019 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/share.h"
-#include "linux/ksmbd_server.h"
-#include "share_admin.h"
-#include "version.h"
-
-static char *arg_name;
-static char *arg_opts;
-
-enum {
-	COMMAND_ADD_SHARE = 1,
-	COMMAND_DEL_SHARE,
-	COMMAND_UPDATE_SHARE,
-};
-
-static void usage(void)
-{
-	int i;
-
-	fprintf(stderr, "Usage: smbshareadd\n");
-
-	fprintf(stderr, "\t-a | --add-share=share\n");
-	fprintf(stderr, "\t-d | --del-share=share\n");
-	fprintf(stderr, "\t-u | --update-share=share\n");
-	fprintf(stderr, "\t-o | --options=\"op1=val1 op2=val2...\"\n");
-
-	fprintf(stderr, "\t-c smb.conf\n");
-	fprintf(stderr, "\t-V | --version\n");
-	fprintf(stderr, "\t-v | --verbose\n");
-
-	fprintf(stderr, "Supported share options:\n");
-	for (i = 0; i < KSMBD_SHARE_CONF_MAX; i++)
-		fprintf(stderr, "\t%s\n", KSMBD_SHARE_CONF[i]);
-	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 *smbconf)
-{
-	int ret;
-
-	ret = test_file_access(smbconf);
-	if (ret)
-		return ret;
-
-	ret = cp_smbconfig_hash_create(smbconf);
-	if (ret)
-		return ret;
-	return 0;
-}
-
-static int sanity_check_share_name_simple(char *name)
-{
-	int sz, i;
-
-	if (!name)
-		return -EINVAL;
-
-	sz = strlen(name);
-	if (sz < 1)
-		return -EINVAL;
-	if (sz >= KSMBD_REQ_MAX_SHARE_NAME)
-		return -EINVAL;
-
-	if (!cp_key_cmp(name, "global"))
-		return -EINVAL;
-
-	return -EINVAL;
-}
-
-int main(int argc, char *argv[])
-{
-	int ret = EXIT_FAILURE;
-	char *smbconf = PATH_SMBCONF;
-	int c, cmd = 0;
-
-	set_logger_app_name("ksmbd.addshare");
-
-	opterr = 0;
-	while ((c = getopt(argc, argv, "c:a:d:u:p:o:Vvh")) != EOF)
-		switch (c) {
-		case 'a':
-			arg_name = g_ascii_strdown(optarg, strlen(optarg));
-			cmd = COMMAND_ADD_SHARE;
-			break;
-		case 'd':
-			arg_name = g_ascii_strdown(optarg, strlen(optarg));
-			cmd = COMMAND_DEL_SHARE;
-			break;
-		case 'u':
-			arg_name = g_ascii_strdown(optarg, strlen(optarg));
-			cmd = COMMAND_UPDATE_SHARE;
-			break;
-		case 'c':
-			smbconf = strdup(optarg);
-			break;
-		case 'o':
-			arg_opts = strdup(optarg);
-			break;
-		case 'V':
-			show_version();
-			break;
-		case 'v':
-			break;
-		case '?':
-		case 'h':
-		default:
-			usage();
-	}
-
-	if (cmd != COMMAND_DEL_SHARE && !arg_opts) {
-		usage();
-		return -1;
-	}
-
-	if (sanity_check_share_name_simple(arg_name)) {
-		pr_err("share name sanity check failure\n");
-		goto out;
-	}
-
-	if (!smbconf) {
-		pr_err("Out of memory\n");
-		goto out;
-	}
-
-	ret = parse_configs(smbconf);
-	if (ret) {
-		pr_err("Unable to parse configuration files\n");
-		goto out;
-	}
-
-	if (cmd == COMMAND_ADD_SHARE)
-		ret = command_add_share(smbconf, arg_name, arg_opts);
-	if (cmd == COMMAND_DEL_SHARE)
-		ret = command_del_share(smbconf, arg_name);
-	if (cmd == COMMAND_UPDATE_SHARE)
-		ret = command_update_share(smbconf, arg_name, arg_opts);
-
-	/*
-	 * We support only ADD_SHARE command for the time being
-	 */
-	if (ret == 0 && cmd == COMMAND_ADD_SHARE)
-		notify_ksmbd_daemon();
-out:
-	cp_smbconfig_destroy();
-	return ret;
-}
diff --git a/share/share.c b/share/share.c
new file mode 100644
index 000000000000..91d23d28c426
--- /dev/null
+++ b/share/share.c
@@ -0,0 +1,227 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *   Copyright (C) 2019 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/share.h"
+#include "linux/ksmbd_server.h"
+#include "share_admin.h"
+
+static ksmbd_share_cmd ksmbd_share_get_cmd(char *cmd)
+{
+	int i;
+
+	if (!cmd)
+		return KSMBD_CMD_SHARE_NONE;
+
+	for (i = 1; i < KSMBD_CMD_SHARE_MAX; i++)
+		if (!strcmp(cmd, ksmbd_share_cmds_str[i]))
+			return (ksmbd_share_cmd)i;
+
+	return KSMBD_CMD_SHARE_NONE;
+}
+
+static const char *ksmbd_share_get_cmd_str(ksmbd_share_cmd cmd)
+{
+	if (cmd > KSMBD_CMD_SHARE_MAX)
+		return ksmbd_share_cmds_str[KSMBD_CMD_SHARE_NONE];
+
+	return ksmbd_share_cmds_str[(int)cmd];
+}
+
+static int parse_configs(char *smbconf)
+{
+	int ret;
+
+	ret = test_file_access(smbconf);
+	if (ret)
+		return ret;
+
+	ret = cp_smbconfig_hash_create(smbconf);
+	if (ret)
+		return ret;
+	return 0;
+}
+
+static int sanity_check_share_name_simple(char *name)
+{
+	int sz, i;
+
+	if (!name)
+		return -EINVAL;
+
+	sz = strlen(name);
+	if (sz < 1)
+		return -EINVAL;
+	if (sz >= KSMBD_REQ_MAX_SHARE_NAME)
+		return -EINVAL;
+
+	if (!cp_key_cmp(name, "global"))
+		return -EINVAL;
+
+	for (i = 0; i < sz; i++) {
+		if (isalnum(name[i]))
+			return 0;
+	}
+	return -EINVAL;
+}
+
+void share_usage(ksmbd_share_cmd cmd)
+{
+	int i;
+	const char *cmd_str = ksmbd_share_get_cmd_str(cmd);
+
+	switch (cmd) {
+	case KSMBD_CMD_SHARE_ADD:
+	case KSMBD_CMD_SHARE_UPDATE:
+		pr_out("Usage: ksmbdctl share %s <share_name> [-c <file>] -o \"op1=val1,op2=val2,...\"\n", cmd_str);
+		pr_out("Adds or updates a share to smb.conf file.\n\n");
+		pr_out("%-30s%s", "  -c, --conf=<file>", "Use <file> as smb.conf\n");
+		pr_out("%-30s%s", "  -o, --options=<options>", "Specify options for share\n\n");
+		pr_out("Supported share options:\n");
+		for (i = 0; i < KSMBD_SHARE_CONF_MAX; i++)
+			pr_out("%s\n", KSMBD_SHARE_CONF[i]);
+		break;
+	case KSMBD_CMD_SHARE_DELETE:
+		pr_out("Usage: ksmbdctl share delete <share_name>\n");
+		pr_out("Deletes a share.\n\n");
+		break;
+	default:
+		pr_out("Usage: ksmbdctl share <subcommand> <args> [options]\n");
+		pr_out("Share management.\n\n");
+		pr_out("List of available subcommands:\n");
+		pr_out("%-20s%s", "  add", "Add a share\n");
+		pr_out("%-20s%s", "  delete", "Delete a share\n");
+		pr_out("%-20s%s", "  update", "Update a share\n");
+		pr_out("%-20s%s", "  list", "List the names of all shares available\n\n");
+		break;
+	}
+
+	exit(EXIT_FAILURE);
+}
+
+int share_cmd(int argc, char *argv[])
+{
+	int ret = EXIT_FAILURE;
+	char *smbconf = PATH_SMBCONF;
+	char *share_name = NULL;
+	char *options = NULL;
+	ksmbd_share_cmd cmd = KSMBD_CMD_SHARE_NONE;
+	int c;
+
+	if (argc < 2)
+		goto usage;
+
+	set_logger_app_name("ksmbd-share");
+
+	cmd = ksmbd_share_get_cmd(argv[1]);
+
+	if (cmd == KSMBD_CMD_SHARE_NONE)
+		goto usage;
+
+	if(argc == 2 && cmd != KSMBD_CMD_SHARE_LIST)
+		goto missing_arg;
+
+	if (argv[2] && argv[2][0] != '-')
+		share_name = g_ascii_strdown(argv[2], strlen(argv[2]));
+	else if (cmd != KSMBD_CMD_SHARE_LIST)
+		goto usage;
+
+	optind = 1;
+	while ((c = getopt_long(argc, argv, "-:c:o:", share_opts, NULL)) != EOF)
+		switch (c) {
+		case 1:
+			break;
+		case 'c':
+			if (cmd == KSMBD_CMD_SHARE_DELETE)
+				continue;
+			smbconf = strdup(optarg);
+			break;
+		case 'o':
+			if (cmd == KSMBD_CMD_SHARE_DELETE || cmd == KSMBD_CMD_SHARE_LIST)
+				continue;
+			options = strdup(optarg);
+			break;
+		case ':':
+		case '?':
+		default:
+			goto usage;
+		}
+
+	if (cmd == KSMBD_CMD_SHARE_LIST)
+		goto share_list;
+
+	if (!share_name)
+		goto missing_arg;
+
+	if (cmd != KSMBD_CMD_SHARE_DELETE && !options) {
+		pr_out("Subcommand \"%s\" requires '-o' option set.\n\n", ksmbd_share_get_cmd_str(cmd));
+		goto usage;
+	}
+
+	if (sanity_check_share_name_simple(share_name)) {
+		pr_err("Share name (%s) sanity check failure\n", share_name);
+		goto out;
+	}
+
+share_list:
+	if (!smbconf) {
+		pr_err("Out of memory\n");
+		goto out;
+	}
+
+	ret = parse_configs(smbconf);
+	if (ret) {
+		pr_err("Unable to parse configuration file %s\n", smbconf);
+		goto out;
+	}
+
+	switch (cmd) {
+	case KSMBD_CMD_SHARE_ADD:
+		ret = share_add_cmd(smbconf, share_name, options);
+		break;
+	case KSMBD_CMD_SHARE_DELETE:
+		ret = share_delete_cmd(smbconf, share_name);
+		break;
+	case KSMBD_CMD_SHARE_UPDATE:
+		ret = share_update_cmd(smbconf, share_name, options);
+		break;
+	case KSMBD_CMD_SHARE_LIST:
+		ret = share_list_cmd(smbconf);
+		break;
+	}
+
+	/*
+	 * FIXME: We support only ADD_SHARE command for the time being
+	 */
+	if (ret == 0 && cmd == KSMBD_CMD_SHARE_ADD)
+		notify_ksmbd_daemon();
+
+out:
+	cp_smbconfig_destroy();
+	return ret;
+missing_arg:
+	if (cmd > KSMBD_CMD_SHARE_NONE && cmd < KSMBD_CMD_SHARE_MAX)
+		pr_out("Subcommand \"%s\" requires an argument.\n\n", ksmbd_share_get_cmd_str(cmd));
+usage:
+	share_usage(cmd);
+
+	return ret;
+}
diff --git a/share/share_admin.c b/share/share_admin.c
index 0ff13d8017dd..61780fb00b5a 100644
--- a/share/share_admin.c
+++ b/share/share_admin.c
@@ -1,12 +1,14 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
  *   Copyright (C) 2019 Samsung Electronics Co., Ltd.
+ *   Copyright (C) 2021 SUSE LLC
  *
  *   linux-cifsd-devel@lists.sourceforge.net
  */
 
 #include <glib.h>
 #include <stdlib.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <getopt.h>
@@ -48,24 +50,26 @@ static char *aux_group_name(char *name)
 	return gn;
 }
 
-static int __open_smbconf(char *smbconf)
+static int open_smbconf(char *smbconf, bool truncate)
 {
-	conf_fd = open(smbconf, O_WRONLY);
+	conf_fd = open(smbconf, O_RDWR);
 	if (conf_fd == -1) {
 		pr_err("%s %s\n", strerr(errno), smbconf);
 		return -EINVAL;
 	}
 
-	if (ftruncate(conf_fd, 0)) {
-		pr_err("%s %s\n", strerr(errno), smbconf);
-		close(conf_fd);
-		return -EINVAL;
+	if (truncate) {
+		if (ftruncate(conf_fd, 0)) {
+			pr_err("%s %s\n", strerr(errno), smbconf);
+			close(conf_fd);
+			return -EINVAL;
+		}
 	}
 
 	return 0;
 }
 
-static void __write(void)
+static void do_write(void)
 {
 	int nr = 0;
 	int ret;
@@ -83,7 +87,7 @@ static void __write(void)
 	}
 }
 
-static void __write_share(gpointer key, gpointer value, gpointer buf)
+static void write_share(gpointer key, gpointer value, gpointer buf)
 {
 	char *k = (char *)key;
 	char *v = (char *)value;
@@ -95,14 +99,14 @@ static void __write_share(gpointer key, gpointer value, gpointer buf)
 			sizeof(wbuf));
 		exit(EXIT_FAILURE);
 	}
-	__write();
+	do_write();
 }
 
-static void write_share(struct smbconf_group *g)
+static void write_share_all(struct smbconf_group *g)
 {
 	wsz = snprintf(wbuf, sizeof(wbuf), "[%s]\n", g->name);
-	__write();
-	g_hash_table_foreach(g->kv, __write_share, NULL);
+	do_write();
+	g_hash_table_foreach(g->kv, write_share, NULL);
 }
 
 static void write_share_cb(gpointer key, gpointer value, gpointer share_data)
@@ -113,7 +117,7 @@ static void write_share_cb(gpointer key, gpointer value, gpointer share_data)
 	 * Do not write AUX group
 	 */
 	if (!strstr(g->name, AUX_GROUP_PREFIX))
-		write_share(g);
+		write_share_all(g);
 }
 
 static void write_remove_share_cb(gpointer key,
@@ -127,7 +131,7 @@ static void write_remove_share_cb(gpointer key,
 		return;
 	}
 
-	write_share(g);
+	write_share_all(g);
 }
 
 static void update_share_cb(gpointer key,
@@ -145,12 +149,32 @@ static void update_share_cb(gpointer key,
 	g_hash_table_insert(g, nk, nv);
 }
 
-int command_add_share(char *smbconf, char *name, char *opts)
+static void list_shares_cb(gpointer key, gpointer value, gpointer data)
+{
+	char *nk, *nv;
+
+	nk = g_strdup(key);
+	nv = g_strdup(value);
+
+	if (!nk || !nv)
+		exit(EXIT_FAILURE);
+
+	if (!strcmp(nk, "global"))
+		goto out;
+
+	pr_out("%s\n", nk);
+
+out:
+	g_free(nk);
+	g_free(nv);
+}
+
+int share_add_cmd(char *smbconf, char *name, char *opts)
 {
 	char *new_name = NULL;
 
 	if (g_hash_table_lookup(parser.groups, name)) {
-		pr_err("Share already exists: %s\n", name);
+		pr_warn("Share already exists: %s\n", name);
 		return -EEXIST;
 	}
 
@@ -158,7 +182,7 @@ int command_add_share(char *smbconf, char *name, char *opts)
 	if (cp_parse_external_smbconf_group(new_name, opts))
 		goto error;
 
-	if (__open_smbconf(smbconf))
+	if (open_smbconf(smbconf, true))
 		goto error;
 	g_hash_table_foreach(parser.groups, write_share_cb, NULL);
 	close(conf_fd);
@@ -170,7 +194,7 @@ error:
 	return -EINVAL;
 }
 
-int command_update_share(char *smbconf, char *name, char *opts)
+int share_update_cmd(char *smbconf, char *name, char *opts)
 {
 	struct smbconf_group *existing_group;
 	struct smbconf_group *update_group;
@@ -198,7 +222,7 @@ int command_update_share(char *smbconf, char *name, char *opts)
 			     update_share_cb,
 			     existing_group->kv);
 
-	if (__open_smbconf(smbconf))
+	if (open_smbconf(smbconf, true))
 		goto error;
 
 	g_hash_table_foreach(parser.groups, write_share_cb, NULL);
@@ -211,9 +235,9 @@ error:
 	return -EINVAL;
 }
 
-int command_del_share(char *smbconf, char *name)
+int share_delete_cmd(char *smbconf, char *name)
 {
-	if (__open_smbconf(smbconf))
+	if (open_smbconf(smbconf, true))
 		return -EINVAL;
 
 	g_hash_table_foreach(parser.groups,
@@ -222,3 +246,22 @@ int command_del_share(char *smbconf, char *name)
 	close(conf_fd);
 	return 0;
 }
+
+int share_list_cmd(char *smbconf)
+{
+	if (open_smbconf(smbconf, false))
+		return -EINVAL;
+
+	if (g_hash_table_size(parser.groups) <= 1) {
+		pr_out("No shares available in %s.\n", smbconf);
+		goto out;
+	}
+
+	pr_out("Shares available in %s:\n", smbconf);
+	g_hash_table_foreach(parser.groups,
+			     list_shares_cb,
+			     NULL);
+out:
+	close(conf_fd);
+	return 0;
+}
diff --git a/share/share_admin.h b/share/share_admin.h
index 7df3871bfe81..00cf1147af18 100644
--- a/share/share_admin.h
+++ b/share/share_admin.h
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-or-later */
 /*
  *   Copyright (C) 2019 Samsung Electronics Co., Ltd.
+ *   Copyright (C) 2021 SUSE LLC
  *
  *   linux-cifsd-devel@lists.sourceforge.net
  */
@@ -8,8 +9,36 @@
 #ifndef __KSMBD_SHARE_ADMIN_H__
 #define __KSMBD_SHARE_ADMIN_H__
 
-int command_add_share(char *smbconf, char *name, char *opts);
-int command_update_share(char *smbconf, char *name, char *opts);
-int command_del_share(char *smbconf, char *name);
+int share_add_cmd(char *smbconf, char *name, char *opts);
+int share_delete_cmd(char *smbconf, char *name);
+int share_update_cmd(char *smbconf, char *name, char *opts);
+int share_list_cmd(char *smbconf);
+
+typedef enum {
+	KSMBD_CMD_SHARE_NONE = 0,
+	KSMBD_CMD_SHARE_ADD,
+	KSMBD_CMD_SHARE_DELETE,
+	KSMBD_CMD_SHARE_UPDATE,
+	KSMBD_CMD_SHARE_LIST,
+	KSMBD_CMD_SHARE_MAX
+} ksmbd_share_cmd;
+
+/* List of supported subcommands */
+static const char *ksmbd_share_cmds_str[] = {
+	"none",
+	"add",
+	"delete",
+	"update",
+	"list"
+};
+
+static struct option share_opts[] = {
+        { "conf", required_argument, NULL, 'c' },
+        { "options", required_argument, NULL, 'o' },
+	{ 0, 0, 0, 0 },
+};
+
+void share_usage(ksmbd_share_cmd cmd);
+int share_cmd(int argc, char *argv[]);
 
 #endif /* __KSMBD_SHARE_ADMIN_H__ */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 5/9] user: introduce user_cmd
  2022-03-07  1:33 [PATCH 0/9] Unify all programs into a single binary "ksmbdctl" Enzo Matsumiya
                   ` (3 preceding siblings ...)
  2022-03-07  1:33 ` [PATCH 4/9] share: introduce share_cmd Enzo Matsumiya
@ 2022-03-07  1:33 ` Enzo Matsumiya
  2022-03-10  2:17   ` Namjae Jeon
  2022-03-07  1:33 ` [PATCH 6/9] daemon: introduce daemon_cmd Enzo Matsumiya
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 13+ messages in thread
From: Enzo Matsumiya @ 2022-03-07  1:33 UTC (permalink / raw)
  To: linux-cifs, linkinjeon
  Cc: senozhatsky, sergey.senozhatsky, hyc.lee, smfrench, Enzo Matsumiya

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]))
+			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__ */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 6/9] daemon: introduce daemon_cmd
  2022-03-07  1:33 [PATCH 0/9] Unify all programs into a single binary "ksmbdctl" Enzo Matsumiya
                   ` (4 preceding siblings ...)
  2022-03-07  1:33 ` [PATCH 5/9] user: introduce user_cmd Enzo Matsumiya
@ 2022-03-07  1:33 ` Enzo Matsumiya
  2022-03-07  1:33 ` [PATCH 7/9] daemon/rpc_samr: drop unused function rpc_samr_remove_domain_entry() Enzo Matsumiya
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Enzo Matsumiya @ 2022-03-07  1:33 UTC (permalink / raw)
  To: linux-cifs, linkinjeon
  Cc: senozhatsky, sergey.senozhatsky, hyc.lee, smfrench, Enzo Matsumiya

Implement and improve daemon management commands.

Sets the forked process name to "ksmbd-daemon".

Rename some variables and functions to something more meaningful.

Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
---
 daemon/daemon.c      | 320 ++++++++++++++++++++++++++++---------------
 daemon/daemon.h      |  26 ++++
 daemon/ipc.c         |   9 +-
 daemon/rpc.c         |   6 +-
 daemon/worker.c      |  13 +-
 include/ksmbdtools.h |   2 +-
 6 files changed, 248 insertions(+), 128 deletions(-)

diff --git a/daemon/daemon.c b/daemon/daemon.c
index 50afbd2ed70d..533b2bf9de0f 100644
--- a/daemon/daemon.c
+++ b/daemon/daemon.c
@@ -6,7 +6,7 @@
  *   linux-cifsd-devel@lists.sourceforge.net
  */
 
-#include <ksmbdtools.h>
+#include "ksmbdtools.h"
 
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE
@@ -20,6 +20,7 @@
 #include <fcntl.h>
 #include <sys/file.h>
 #include <sys/types.h>
+#include <sys/prctl.h>
 #include <sys/wait.h>
 #include <signal.h>
 
@@ -35,53 +36,85 @@
 #include "management/spnego.h"
 #include "version.h"
 
-static int no_detach = 0;
 int ksmbd_health_status;
 static pid_t worker_pid;
 static int lock_fd = -1;
 
-typedef int (*worker_fn)(void);
+typedef int (*worker_fn)(void *);
 
-static void usage(void)
+static ksmbd_daemon_cmd ksmbd_daemon_get_cmd(char *cmd)
 {
-	fprintf(stderr, "Usage: ksmbd\n");
-	fprintf(stderr, "\t--p=NUM | --port=NUM              TCP port NUM\n");
-	fprintf(stderr, "\t--c=smb.conf | --config=smb.conf  config file\n");
-	fprintf(stderr, "\t--u=pwd.db | --users=pwd.db       Users DB\n");
-	fprintf(stderr, "\t--n | --nodetach                  Don't detach\n");
-	fprintf(stderr, "\t--s | --systemd                   Service mode\n");
-	fprintf(stderr, "\t-V | --version                    Show version\n");
-	fprintf(stderr, "\t-h | --help                       Show help\n");
+	int i;
 
-	exit(EXIT_FAILURE);
+	if (!cmd)
+		return KSMBD_CMD_DAEMON_NONE;
+
+	for (i = 0; i < KSMBD_CMD_DAEMON_MAX; i++)
+		if (!strcmp(cmd, ksmbd_daemon_cmds_str[i]))
+			return (ksmbd_daemon_cmd)i;
+
+	return KSMBD_CMD_DAEMON_NONE;
+}
+
+static const char *ksmbd_daemon_get_cmd_str(ksmbd_daemon_cmd cmd)
+{
+	if (cmd > KSMBD_CMD_DAEMON_MAX)
+		return ksmbd_daemon_cmds_str[KSMBD_CMD_DAEMON_NONE];
+
+	return ksmbd_daemon_cmds_str[(int)cmd];
 }
 
-static void show_version(void)
+void daemon_usage(ksmbd_daemon_cmd cmd)
 {
-	printf("ksmbd-tools version : %s\n", KSMBD_TOOLS_VERSION);
+	const char *cmd_str = ksmbd_daemon_get_cmd_str(cmd);
+	int i;
+
+	switch(cmd) {
+	case KSMBD_CMD_DAEMON_START:
+		pr_out("Usage: ksmbdctl daemon start [options]\n");
+		pr_out("Start ksmbd userspace and kernel daemon.\n\n");
+		pr_out("%-30s%s", "  -p, --port=<num>", "TCP port number to listen on\n");
+		pr_out("%-30s%s", "  -c, --config=<config>", "Use specified smb.conf file\n");
+		pr_out("%-30s%s", "  -u, --usersdb=<config>", "Use specified users DB file\n");
+		pr_out("%-30s%s", "  -n, --nodetach", "Don't detach\n");
+		pr_out("%-30s%s", "  -s, --systemd", "Start daemon in systemd service mode\n");
+		pr_out("%-30s%s", "  -h, --help", "Show this help menu\n\n");
+		break;
+	case KSMBD_CMD_DAEMON_SHUTDOWN:
+		pr_out("Usage: ksmbdctl daemon shutdown\n");
+		pr_out("Shuts down the userspace daemon and the kernel server.\n\n");
+		break;
+	case KSMBD_CMD_DAEMON_DEBUG:
+		pr_out("Usage: ksmbdctl daemon debug <type>\n");
+		pr_out("Enable/disable debugging modules for ksmbd.\n\n");
+		pr_out("List of available types:\n");
+		for (i = 0; i < ARRAY_SIZE(debug_type_strings); i++)
+			pr_out("%s ", debug_type_strings[i]);
+		pr_out("\n\n");
+		break;
+	default:
+		pr_out("Usage: ksmbdctl daemon <subcommand> <args> [options]\n");
+		pr_out("ksmbd daemon management.\n\n");
+		pr_out("List of available subcommands:\n");
+		pr_out("%-20s%s", "start", "Start ksmbd userspace daemon\n");
+		pr_out("%-20s%s", "shutdown", "Shutdown ksmbd userspace daemon\n");
+		pr_out("%-20s%s", "debug", "Enable/disable debugging for ksmbd components\n\n");
+		break;
+	}
+
 	exit(EXIT_FAILURE);
 }
 
 static int handle_orphaned_lock_file(void)
 {
-	char proc_ent[64] = {0, };
-	char manager_pid[10] = {0, };
-	int pid = 0;
+	char proc_ent[64] = { 0 };
+	pid_t pid;
 	int fd;
 
-	fd = open(KSMBD_LOCK_FILE, O_RDONLY);
-	if (fd < 0)
+	pid = get_running_pid();
+	if (pid < 0)
 		return -EINVAL;
 
-	if (read(fd, &manager_pid, sizeof(manager_pid)) == -1) {
-		pr_debug("Unable to read main PID: %s\n", strerr(errno));
-		close(fd);
-		return -EINVAL;
-	}
-
-	close(fd);
-
-	pid = strtol(manager_pid, NULL, 10);
 	snprintf(proc_ent, sizeof(proc_ent), "/proc/%d", pid);
 	fd = open(proc_ent, O_RDONLY);
 	if (fd < 0) {
@@ -91,17 +124,19 @@ static int handle_orphaned_lock_file(void)
 
 	close(fd);
 	pr_info("File '%s' belongs to pid %d\n", KSMBD_LOCK_FILE, pid);
+
 	return -EINVAL;
 }
 
 static int create_lock_file(void)
 {
-	char manager_pid[10];
-	size_t sz;
+	char daemon_pid[10];
+	size_t len;
 
 retry:
 	lock_fd = open(KSMBD_LOCK_FILE, O_CREAT | O_EXCL | O_WRONLY,
 			S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
+
 	if (lock_fd < 0) {
 		if (handle_orphaned_lock_file())
 			return -EINVAL;
@@ -111,9 +146,10 @@ retry:
 	if (flock(lock_fd, LOCK_EX | LOCK_NB) != 0)
 		return -EINVAL;
 
-	sz = snprintf(manager_pid, sizeof(manager_pid), "%d", getpid());
-	if (write(lock_fd, manager_pid, sz) == -1)
+	len = snprintf(daemon_pid, sizeof(daemon_pid), "%d", getpid());
+	if (write(lock_fd, daemon_pid, len) == -1)
 		pr_err("Unable to record main PID: %s\n", strerr(errno));
+
 	return 0;
 }
 
@@ -147,7 +183,7 @@ char *make_path_subauth(void)
  * Avoids a corrupt file if the write would be interrupted due
  * to a power failure.
  */
-static int write_file_safe(char *path, char *buff, size_t length, int mode)
+static int write_file_safe(char *path, char *buff, size_t len, int mode)
 {
 	int fd, ret = -1;
 	char *path_tmp = g_strdup_printf("%s.tmp", path);
@@ -161,7 +197,7 @@ static int write_file_safe(char *path, char *buff, size_t length, int mode)
 		goto err_out;
 	}
 
-	if (write(fd, buff, length) == -1) {
+	if (write(fd, buff, len) == -1) {
 		pr_err("Unable to write to %s: %s\n", path_tmp, strerr(errno));
 		close(fd);
 		goto err_out;
@@ -204,9 +240,8 @@ static int generate_sub_auth(void)
 	if (!path_subauth)
 		return -ENOMEM;
 retry:
-	if (g_file_test(path_subauth, G_FILE_TEST_EXISTS)) {
+	if (g_file_test(path_subauth, G_FILE_TEST_EXISTS))
 		rc = cp_parse_subauth(path_subauth);
-	}
 
 	if (rc < 0) {
 		rc = create_subauth_file(path_subauth);
@@ -238,14 +273,14 @@ static int wait_group_kill(int signo)
 	int status;
 
 	if (kill(worker_pid, signo) != 0)
-		pr_err("can't execute kill %d: %s\n",
+		pr_warn("can't execute kill %d: %s\n",
 			worker_pid,
 			strerr(errno));
 
 	while (1) {
 		pid = waitpid(-1, &status, 0);
 		if (pid != 0) {
-			pr_debug("detected pid %d termination\n", pid);
+			pr_debug("Detected pid %d termination\n", pid);
 			break;
 		}
 		sleep(1);
@@ -297,16 +332,16 @@ static int parse_configs(char *db, char *smbconf)
 
 	ret = cp_parse_db(db);
 	if (ret == -ENOENT) {
-		pr_err("User database file does not exist. %s\n",
+		pr_warn("User database file does not exist. %s\n",
 			"Only guest sessions (if permitted) will work.");
 	} else if (ret) {
-		pr_err("Unable to parse user database\n");
+		pr_err("Unable to parse user database %s\n", db);
 		return ret;
 	}
 
 	ret = cp_parse_smbconf(smbconf);
 	if (ret) {
-		pr_err("Unable to parse smb configuration file\n");
+		pr_err("Unable to parse configuration file %s\n", smbconf);
 		return ret;
 	}
 	return 0;
@@ -353,7 +388,7 @@ static void child_sig_handler(int signo)
 	exit(EXIT_SUCCESS);
 }
 
-static void manager_sig_handler(int signo)
+static void daemon_sig_handler(int signo)
 {
 	/*
 	 * Pass SIGHUP to worker, so it will reload configs
@@ -376,7 +411,7 @@ static void manager_sig_handler(int signo)
 	kill(0, SIGINT);
 }
 
-static int worker_process_init(void)
+static int worker_process_init(void *data)
 {
 	int ret;
 
@@ -395,7 +430,7 @@ static int worker_process_init(void)
 		goto out;
 	}
 
-	ret = parse_configs(global_conf.db, global_conf.smbconf);
+	ret = parse_configs(global_conf.users_db, global_conf.smbconf);
 	if (ret) {
 		pr_err("Failed to parse configuration files\n");
 		goto out;
@@ -444,32 +479,40 @@ out:
 	return ret;
 }
 
-static pid_t start_worker_process(worker_fn fn)
+static pid_t start_worker_process(worker_fn fn, void *data)
 {
 	int status = 0;
-	pid_t __pid;
+	pid_t pid;
 
-	__pid = fork();
-	if (__pid < 0) {
+	pid = fork();
+	if (pid < 0) {
 		pr_err("Can't fork child process: `%s'\n", strerr(errno));
 		return -EINVAL;
 	}
-	if (__pid == 0) {
-		status = fn();
+	if (pid == 0) {
+		status = fn(data);
 		exit(status);
 	}
-	return __pid;
+
+	return pid;
 }
 
-static int manager_process_init(void)
+static int daemon_process_start(void *data)
 {
+	int no_detach;
 	/*
 	 * Do not chdir() daemon()'d process to '/'.
 	 */
 	int nochdir = 1;
 
-	setup_signals(manager_sig_handler);
-	if (no_detach == 0) {
+	if(prctl(PR_SET_NAME, "ksmbd-daemon\0", 0, 0, 0))
+		pr_info("Can't set program name: %s\n", strerr(errno));
+
+	if (data)
+		no_detach = *(int *)data;
+
+	setup_signals(daemon_sig_handler);
+	if (!no_detach) {
 		pr_logger_init(PR_LOGGER_SYSLOG);
 		if (daemon(nochdir, 0) != 0) {
 			pr_err("Daemonization failed\n");
@@ -481,7 +524,7 @@ static int manager_process_init(void)
 		 * the group leader already then the function will do
 		 * nothing (apart from setting errnor to EPERM).
 		 */
-		if (no_detach == 1)
+		if (no_detach)
 			setsid();
 	}
 
@@ -494,7 +537,7 @@ static int manager_process_init(void)
 		pr_debug("Failed to generate subauth for domain sid: %s\n",
 				strerr(errno));
 
-	worker_pid = start_worker_process(worker_process_init);
+	worker_pid = start_worker_process(worker_process_init, NULL);
 	if (worker_pid < 0)
 		goto out;
 
@@ -509,8 +552,7 @@ static int manager_process_init(void)
 			continue;
 		}
 
-		pr_err("WARNING: child process exited abnormally: %d\n",
-				child);
+		pr_warn("child process exited abnormally: %d\n", child);
 		if (child == -1) {
 			pr_err("waitpid() returned error code: %s\n",
 				strerr(errno));
@@ -525,7 +567,7 @@ static int manager_process_init(void)
 
 		/* Ratelimit automatic restarts */
 		sleep(1);
-		worker_pid = start_worker_process(worker_process_init);
+		worker_pid = start_worker_process(worker_process_init, NULL);
 		if (worker_pid < 0)
 			goto out;
 	}
@@ -535,35 +577,34 @@ out:
 	return 0;
 }
 
-static int manager_systemd_service(void)
+int daemon_start_cmd(int no_detach, int systemd_service)
 {
-	pid_t __pid;
+	pid_t pid;
+	int ret = -EINVAL;
+
+	/* Check if process is already running */
+	pid = get_running_pid();
+	if (pid > 1) {
+		pr_err("ksmbd-daemon already running (%d)\n", pid);
+		exit(EXIT_FAILURE);
+	}
+
+	if (!systemd_service)
+		return daemon_process_start((void *)&no_detach);
 
-	__pid = start_worker_process(manager_process_init);
-	if (__pid < 0)
+	pid = start_worker_process(daemon_process_start, (void *)&no_detach);
+	if (pid < 0)
 		return -EINVAL;
 
 	return 0;
 }
 
-static struct option opts[] = {
-	{"port",	required_argument,	NULL,	'p' },
-	{"config",	required_argument,	NULL,	'c' },
-	{"users",	required_argument,	NULL,	'u' },
-	{"systemd",	no_argument,		NULL,	's' },
-	{"nodetach",	optional_argument,	NULL,	'n' },
-	{"help",	no_argument,		NULL,	'h' },
-	{"?",		no_argument,		NULL,	'?' },
-	{"version",	no_argument,		NULL,	'V' },
-	{NULL,		0,			NULL,	 0  }
-};
-
 int daemon_shutdown_cmd(void)
 {
 	int fd, ret;
 
 	if (get_running_pid() == -ENOENT) {
-		pr_info("Server is not running.\n");
+		pr_out("Server is not running.\n");
 		exit(EXIT_FAILURE);
 	}
 
@@ -613,7 +654,7 @@ err:
 	close(fd);
 err_open:
 	if (ret == -EBADF)
-		pr_debug("Can't open %s. Is ksmbd kernel module loaded?\n");
+		pr_debug("Can't open %s. Is ksmbd kernel module loaded?\n", KSMBD_SYSFS_DEBUG);
 	return ret;
 }
 
@@ -633,74 +674,125 @@ err:
 	if (ret < 0)
 		pr_err("%s. Is kernel module loaded?\n", strerr(errno));
 	else
-		pr_info("ksmbd module version: %s\n", version);
+		pr_out("ksmbd module version: %s\n", version);
 
 	return ret;
 }
 
-int main(int argc, char *argv[])
+int daemon_cmd(int argc, char *argv[])
 {
+	int ret = EXIT_FAILURE;
+	int no_detach = 0;
 	int systemd_service = 0;
-	int c;
+	char *debug_type;
+	const char *cmd_str;
+	ksmbd_daemon_cmd cmd = KSMBD_CMD_DAEMON_NONE;
+	int c, i;
+
+	if (argc < 2)
+		goto usage;
+
+	set_logger_app_name("ksmbd-daemon");
+
+	cmd = ksmbd_daemon_get_cmd(argv[1]);
+	cmd_str = ksmbd_daemon_get_cmd_str(cmd);
+
+	if (cmd == KSMBD_CMD_DAEMON_NONE)
+		goto usage;
+
+	if (cmd == KSMBD_CMD_DAEMON_VERSION ||
+	    cmd == KSMBD_CMD_DAEMON_SHUTDOWN)
+		goto skip_opts;
+
+	if (cmd == KSMBD_CMD_DAEMON_DEBUG) {
+		if (argc == 2)
+			goto usage;
+
+		debug_type = strdup(argv[2]);
+
+		ret = daemon_debug_cmd(debug_type);
+		if (ret == -EINVAL) {
+			pr_out("Invalid debug type \"%s\"\n\n", debug_type);
+			pr_out("List of available types:\n");
+			for (i = 0; i < ARRAY_SIZE(debug_type_strings); i++)
+				pr_out("%s ", debug_type_strings[i]);
+			pr_out("\n\n");
+		} else if (ret < 0) {
+			pr_out("Error enabling/disabling ksmbd debug\n");
+		}
+
+		free(debug_type);
+		return ret;
+	}
 
-	set_logger_app_name("ksmbd.daemon");
 	memset(&global_conf, 0x00, sizeof(struct smbconf_global));
-	global_conf.db = PATH_USERS_DB;
+	global_conf.users_db = PATH_USERS_DB;
 	global_conf.smbconf = PATH_SMBCONF;
-	pr_logger_init(PR_LOGGER_STDIO);
 
-	opterr = 0;
-	while (1) {
-		c = getopt_long(argc, argv, "n::p:c:u:sVh", opts, NULL);
-
-		if (c < 0)
-			break;
+	pr_logger_init(PR_LOGGER_STDIO);
 
-		switch (c) {
-		case 0: /* getopt_long() set a variable, just keep going */
-			break;
+	optind = 1;
+	while ((c = getopt_long(argc, argv, "-:p:c:u:nsh", daemon_opts, NULL)) != EOF)
+		switch(c) {
 		case 1:
 			break;
 		case 'p':
 			global_conf.tcp_port = cp_get_group_kv_long(optarg);
-			pr_debug("TCP port option override\n");
+			pr_info("Overriding TCP port to %hu\n", global_conf.tcp_port);
 			break;
 		case 'c':
 			global_conf.smbconf = g_strdup(optarg);
+			if (!global_conf.smbconf)
+				goto oom;
 			break;
 		case 'u':
-			global_conf.db = g_strdup(optarg);
+			global_conf.users_db = g_strdup(optarg);
+			if (!global_conf.users_db)
+				goto oom;
 			break;
 		case 'n':
-			if (!optarg)
-				no_detach = 1;
-			else
-				no_detach = cp_get_group_kv_long(optarg);
+			no_detach = 1;
 			break;
 		case 's':
 			systemd_service = 1;
 			break;
-		case 'V':
-			show_version();
-			break;
 		case ':':
-			pr_err("Missing option argument\n");
-			/* Fall through */
 		case '?':
 		case 'h':
-			/* Fall through */
 		default:
-			usage();
+			goto usage;
 		}
-	}
 
-	if (!global_conf.smbconf || !global_conf.db) {
-		pr_err("Out of memory\n");
-		exit(EXIT_FAILURE);
+skip_opts:
+	switch (cmd) {
+	case KSMBD_CMD_DAEMON_START:
+		setup_signals(daemon_sig_handler);
+		ret = daemon_start_cmd(no_detach, systemd_service);
+		if (ret != 0) {
+			pr_err("Error starting daemon\n");
+			exit(EXIT_FAILURE);
+		}
+		break;
+	case KSMBD_CMD_DAEMON_SHUTDOWN:
+		ret = daemon_shutdown_cmd();
+		if (ret < 0) {
+			pr_err("Error shutting down server. Is ksmbd kernel module loaded?\n");
+			exit(EXIT_FAILURE);
+		}
+		pr_out("Server was shut down.\n");
+		break;
+	case KSMBD_CMD_DAEMON_VERSION:
+		ret = daemon_version_cmd();
+		break;
 	}
 
-	setup_signals(manager_sig_handler);
-	if (!systemd_service)
-		return manager_process_init();
-	return manager_systemd_service();
+	return ret;
+
+usage:
+	daemon_usage(cmd);
+	exit(EXIT_FAILURE);
+oom:
+	pr_err("Out of memory\n");
+	ret = -ENOMEM;
+	return ret;
 }
diff --git a/daemon/daemon.h b/daemon/daemon.h
index ca064b2b732d..7cfedc100e56 100644
--- a/daemon/daemon.h
+++ b/daemon/daemon.h
@@ -12,10 +12,33 @@
 #define KSMBD_SYSFS_DEBUG	"/sys/class/ksmbd-control/debug"
 #define KSMBD_SYSFS_VERSION	"/sys/module/ksmbd/version"
 
+int daemon_start_cmd(int no_detach, int systemd_service);
+int daemon_shutdown_cmd(void);
+int daemon_debug_cmd(char *debug_type);
+int daemon_version_cmd(void);
+
+typedef enum {
+	KSMBD_CMD_DAEMON_NONE = 0,
+	KSMBD_CMD_DAEMON_START,
+	KSMBD_CMD_DAEMON_SHUTDOWN,
+	KSMBD_CMD_DAEMON_DEBUG,
+	KSMBD_CMD_DAEMON_VERSION,
+	KSMBD_CMD_DAEMON_MAX
+} ksmbd_daemon_cmd;
+
 static const char * const debug_type_strings[] = {
 	"all", "smb", "auth", "vfs", "oplock", "ipc", "conn", "rdma"
 };
 
+/* List of supported subcommands */
+static const char *ksmbd_daemon_cmds_str[] ={
+	"none",
+	"start",
+	"shutdown",
+	"debug",
+	"version",
+};
+
 static struct option daemon_opts[] = {
 	{ "port", required_argument, NULL, 'p' },
 	{ "config", required_argument, NULL, 'c' },
@@ -26,4 +49,7 @@ static struct option daemon_opts[] = {
 	{ 0, 0, 0, 0 },
 };
 
+void daemon_usage(ksmbd_daemon_cmd cmd);
+int daemon_cmd(int argc, char *argv[]);
+
 #endif /* __DAEMON_H__ */
diff --git a/daemon/ipc.c b/daemon/ipc.c
index b793a1e101b0..a5ff31dcb7b0 100644
--- a/daemon/ipc.c
+++ b/daemon/ipc.c
@@ -31,6 +31,7 @@ struct ksmbd_ipc_msg *ipc_msg_alloc(size_t sz)
 	struct ksmbd_ipc_msg *msg;
 	size_t msg_sz = sz + sizeof(struct ksmbd_ipc_msg) + 1;
 
+	/* FIXME: shouldn't we fail here? */
 	if (msg_sz > KSMBD_IPC_MAX_MESSAGE_SIZE)
 		pr_err("IPC message is too large: %zu\n", msg_sz);
 
@@ -71,7 +72,7 @@ static int parse_reload_configs(const char *db, const char *smbconf)
 	usm_remove_all_users();
 	ret = cp_parse_db(db);
 	if (ret == -ENOENT) {
-		pr_err("User database file does not exist. %s\n",
+		pr_warn("User database file does not exist. %s\n",
 		       "Only guest sessions (if permitted) will work.");
 	} else if (ret) {
 		pr_err("Unable to parse user database\n");
@@ -91,7 +92,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.db, global_conf.smbconf);
+		parse_reload_configs(global_conf.users_db, global_conf.smbconf);
 		ksmbd_health_status &= ~KSMBD_SHOULD_RELOAD_CONFIG;
 	}
 
@@ -108,7 +109,7 @@ static int nlink_msg_cb(struct nl_msg *msg, void *arg)
 	struct genlmsghdr *gnlh = genlmsg_hdr(nlmsg_hdr(msg));
 
 	if (gnlh->version != KSMBD_GENL_VERSION) {
-		pr_err("IPC message version mistamtch: %d\n", gnlh->version);
+		pr_err("IPC message version mismatch: %d\n", gnlh->version);
 		return NL_SKIP;
 	}
 
@@ -124,7 +125,7 @@ static int handle_unsupported_event(struct nl_cache_ops *unused,
 				    struct genl_info *info,
 				    void *arg)
 {
-	pr_err("Unsupported IPC event %d, ignore.\n", cmd->c_id);
+	pr_warn("Unsupported IPC event %d, ignore.\n", cmd->c_id);
 	return NL_SKIP;
 }
 
diff --git a/daemon/rpc.c b/daemon/rpc.c
index ab2a7c6dfebe..0dbbbe6e9be7 100644
--- a/daemon/rpc.c
+++ b/daemon/rpc.c
@@ -588,7 +588,7 @@ static int __max_entries(struct ksmbd_dcerpc *dce, struct ksmbd_rpc_pipe *pipe)
 		return pipe->num_entries;
 
 	if (!dce->entry_size) {
-		pr_err("No ->entry_size() callback was provided\n");
+		pr_warn("No ->entry_size() callback was provided\n");
 		return pipe->num_entries;
 	}
 
@@ -1135,7 +1135,7 @@ int rpc_write_request(struct ksmbd_rpc_command *req,
 		return KSMBD_RPC_OK;
 
 	if (pipe->num_entries)
-		pr_err("RPC: A call on unflushed pipe. Pending %d\n",
+		pr_warn("RPC: A call on unflushed pipe. Pending %d\n",
 			pipe->num_entries);
 
 	dce = pipe->dce;
@@ -1208,6 +1208,6 @@ int rpc_close_request(struct ksmbd_rpc_command *req,
 		return 0;
 	}
 
-	pr_err("RPC: unknown pipe ID: %d\n", req->handle);
+	pr_warn("RPC: unknown pipe ID: %d\n", req->handle);
 	return KSMBD_RPC_OK;
 }
diff --git a/daemon/worker.c b/daemon/worker.c
index 0ddd88cea12c..eb9e646d4985 100644
--- a/daemon/worker.c
+++ b/daemon/worker.c
@@ -329,16 +329,17 @@ int wp_init(void)
 				 MAX_WORKER_THREADS,
 				 0,
 				 &err);
-	if (!pool) {
-		if (err) {
-			pr_err("Can't create pool: %s\n", err->message);
-			g_error_free(err);
-		}
+	if (!pool)
 		goto out_error;
-	}
 
 	return 0;
+
 out_error:
+	if (err) {
+		pr_err("Can't create pool: %s\n", err->message);
+		g_error_free(err);
+	}
+
 	wp_destroy();
 	return -ENOMEM;
 }
diff --git a/include/ksmbdtools.h b/include/ksmbdtools.h
index 978cbe148eac..c9831c16596a 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			*db;
+	char			*users_db;
 	char			*smbconf;
 };
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 7/9] daemon/rpc_samr: drop unused function rpc_samr_remove_domain_entry()
  2022-03-07  1:33 [PATCH 0/9] Unify all programs into a single binary "ksmbdctl" Enzo Matsumiya
                   ` (5 preceding siblings ...)
  2022-03-07  1:33 ` [PATCH 6/9] daemon: introduce daemon_cmd Enzo Matsumiya
@ 2022-03-07  1:33 ` Enzo Matsumiya
  2022-03-07  1:33 ` [PATCH 8/9] Unify all programs into a single binary "ksmbdctl" Enzo Matsumiya
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Enzo Matsumiya @ 2022-03-07  1:33 UTC (permalink / raw)
  To: linux-cifs, linkinjeon
  Cc: senozhatsky, sergey.senozhatsky, hyc.lee, smfrench, Enzo Matsumiya

Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
---
 daemon/rpc_samr.c | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/daemon/rpc_samr.c b/daemon/rpc_samr.c
index 396e38f58013..3e4b2d5dc95b 100644
--- a/daemon/rpc_samr.c
+++ b/daemon/rpc_samr.c
@@ -745,15 +745,6 @@ static int rpc_samr_add_domain_entry(char *name)
 	return 0;
 }
 
-static void rpc_samr_remove_domain_entry(unsigned int eidx)
-{
-	gpointer entry;
-
-	entry = g_array_index(domain_entries, gpointer, eidx);
-	domain_entries = g_array_remove_index(domain_entries, eidx);
-	free(entry);
-}
-
 static void domain_entry_free(void *v)
 {
 	char **entry = v;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 8/9] Unify all programs into a single binary "ksmbdctl"
  2022-03-07  1:33 [PATCH 0/9] Unify all programs into a single binary "ksmbdctl" Enzo Matsumiya
                   ` (6 preceding siblings ...)
  2022-03-07  1:33 ` [PATCH 7/9] daemon/rpc_samr: drop unused function rpc_samr_remove_domain_entry() Enzo Matsumiya
@ 2022-03-07  1:33 ` Enzo Matsumiya
  2022-03-07  1:33 ` [PATCH 9/9] README: change to markdown, updates for ksmbdctl Enzo Matsumiya
  2022-03-10  2:11 ` [PATCH 0/9] Unify all programs into a single binary "ksmbdctl" Namjae Jeon
  9 siblings, 0 replies; 13+ messages in thread
From: Enzo Matsumiya @ 2022-03-07  1:33 UTC (permalink / raw)
  To: linux-cifs, linkinjeon
  Cc: senozhatsky, sergey.senozhatsky, hyc.lee, smfrench, Enzo Matsumiya

This commit unifies all existing programs
(ksmbd.{adduser,addshare,control,mountd}) into a single ksmbdctl binary.

The intention is to make it more like other modern tools (e.g. git,
nvme, virsh, etc) which have more clear user interface, readable
commands, and also makes it easier to script.

Example commands:
  # ksmbdctl share add myshare -o "guest ok=yes, writable=yes, path=/mnt/data"
  # ksmbdctl user add myuser
  # ksmbdctl user add -i $HOME/mysmb.conf anotheruser
  # ksmbdctl daemon start

Besides adding a new "share list" command, any previously working
functionality shouldn't be affected.

Basic testing was done manually.

TODO:
- run more complex tests in more complex environments
- implement unit tests (for each command and subcommand)
- create an abstract command interface, to make it easier to add/modify
  commands

Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
---
 Makefile.am |  14 +++-
 ksmbdctl.c  | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 195 insertions(+), 1 deletion(-)
 create mode 100644 ksmbdctl.c

diff --git a/Makefile.am b/Makefile.am
index b4e205895825..8059a360605b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,7 +2,19 @@
 
 ACLOCAL_AMFLAGS = -I m4
 
-SUBDIRS = lib daemon user share
+SUBDIRS = lib
+AM_CFLAGS = -Iinclude $(GLIB_CFLAGS) $(LIBNL_CFLAGS) -fno-common
+LIBS = $(GLIB_LIBS) $(LIBNL_LIBS) $(LIBKRB5_LIBS)
+ksmbdctl_LDADD = lib/libksmbdtools.a
+
+sbin_PROGRAMS = ksmbdctl
+
+ksmbdctl_SOURCES = share/share_admin.c share/share.c share/share_admin.h \
+		   ksmbdctl.c user/md4_hash.c user/user_admin.c user/user.c \
+		   user/md4_hash.h user/user_admin.h daemon/worker.c \
+		   daemon/ipc.c daemon/rpc.c  daemon/rpc_srvsvc.c \
+		   daemon/rpc_wkssvc.c daemon/daemon.c daemon/smbacl.c \
+		   daemon/rpc_samr.c daemon/rpc_lsarpc.c
 
 # other stuff
 EXTRA_DIST =			\
diff --git a/ksmbdctl.c b/ksmbdctl.c
new file mode 100644
index 000000000000..04e7cd7170fb
--- /dev/null
+++ b/ksmbdctl.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *   Copyright (C) 2021 SUSE LLC
+ *   Author: Enzo Matsumiya <ematsumiya@suse.de>
+ *
+ *   linux-cifsd-devel@lists.sourceforge.net
+ */
+
+#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 <sys/types.h>
+#include <signal.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "config_parser.h"
+#include "ksmbdtools.h"
+#include "management/share.h"
+#include "linux/ksmbd_server.h"
+#include "share/share_admin.h"
+#include "user/user_admin.h"
+#include "daemon/daemon.h"
+#include "version.h"
+
+typedef enum {
+       KSMBD_CMD_NONE = 0,
+       KSMBD_CMD_SHARE,
+       KSMBD_CMD_USER,
+       KSMBD_CMD_DAEMON,
+       KSMBD_CMD_VERSION,
+       KSMBD_CMD_HELP,
+       KSMBD_CMD_MAX
+} ksmbd_cmd;
+
+/* List of supported commands */
+static const char *ksmbd_cmds_str[] = {
+       "none",
+       "share",
+       "user",
+       "daemon",
+       "version",
+       "help"
+};
+
+static ksmbd_cmd ksmbd_get_cmd(char *cmd)
+{
+       int i;
+
+       if (!cmd)
+               return KSMBD_CMD_NONE;
+
+       for (i = 1; i < KSMBD_CMD_MAX; i++)
+               if (!strcmp(cmd, ksmbd_cmds_str[i]))
+                       return (ksmbd_cmd)i;
+
+       return KSMBD_CMD_NONE;
+}
+
+static const char *ksmbd_get_cmd_str(ksmbd_cmd cmd)
+{
+       return ksmbd_cmds_str[(int)cmd];
+}
+
+ksmbd_cmd get_cmd_type(char *cmd)
+{
+       int i;
+
+       if (!cmd)
+               return KSMBD_CMD_NONE;
+
+       for (i = 1; i < KSMBD_CMD_MAX; i++)
+               if (!strcmp(cmd, ksmbd_cmds_str[i]))
+                       return i;
+
+       return KSMBD_CMD_NONE;
+}
+
+static void version(void)
+{
+	pr_out("ksmbd-tools version: %s\n", KSMBD_TOOLS_VERSION);
+}
+
+static void usage(ksmbd_cmd cmd)
+{
+	version();
+
+	switch (cmd) {
+	case KSMBD_CMD_SHARE:
+		share_usage(0);
+		break;
+	case KSMBD_CMD_USER:
+		user_usage(0);
+		break;
+	case KSMBD_CMD_DAEMON:
+		daemon_usage(0);
+		break;
+	case KSMBD_CMD_HELP:
+	default:
+		pr_out("Usage: ksmbdctl [-v] <command> [<option>] <args>\n\n");
+		pr_out("%-20s%s", "  -v", "Enable verbose output. Use -vv or -vvv for more verbose.\n\n");
+		pr_out("List of available commands:\n");
+		pr_out("%-20s%s", "  share", "Manage ksmbd shares\n");
+		pr_out("%-20s%s", "  user", "Manage ksmbd users\n");
+		pr_out("%-20s%s", "  daemon", "Manage ksmbd daemon\n");
+		pr_out("%-20s%s", "  version", "Show ksmbd version\n");
+		pr_out("%-20s%s", "  help", "Show this help menu\n\n");
+		break;
+	}
+
+	exit(EXIT_FAILURE);
+}
+
+int main(int argc, char *argv[])
+{
+	int ret = EXIT_FAILURE;
+	int cmd_argc, c;
+	char **cmd_argv;
+	int verbosity = 0;
+
+	if (geteuid() != 0) {
+		pr_out("You need to be root to run this program.\n");
+		return ret;
+	}
+
+	if (argc < 2)
+		usage(KSMBD_CMD_NONE);
+
+	while ((c = getopt(argc, argv, "-:v")) != EOF)
+		switch (c) {
+		case 'v':
+			verbosity++;
+			break;
+		case 1:
+			goto out_opt;
+			break;
+		case '?':
+		default:
+			usage(KSMBD_CMD_NONE);
+			break;
+		}
+
+out_opt:
+	log_level = verbosity > PR_DEBUG ? PR_DEBUG : verbosity;
+
+	/* check cmd */
+	ksmbd_cmd cmd = get_cmd_type(argv[optind-1]);
+
+	/* strip "ksmbdctl" from argv/argc */
+	cmd_argc = argc - 1;
+	if (verbosity)
+		cmd_argc--;
+
+	cmd_argv = &argv[optind-1];
+
+	switch (cmd) {
+	case KSMBD_CMD_SHARE:
+		ret = share_cmd(cmd_argc, cmd_argv);
+		break;
+	case KSMBD_CMD_USER:
+		ret = user_cmd(cmd_argc, cmd_argv);
+		break;
+	case KSMBD_CMD_DAEMON:
+		ret = daemon_cmd(cmd_argc, cmd_argv);
+		break;
+	case KSMBD_CMD_VERSION:
+		version();
+		break;
+	case KSMBD_CMD_HELP:
+	case KSMBD_CMD_NONE:
+	default:
+		usage(KSMBD_CMD_NONE);
+		break;
+	}
+
+	return ret;
+}
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 9/9] README: change to markdown, updates for ksmbdctl
  2022-03-07  1:33 [PATCH 0/9] Unify all programs into a single binary "ksmbdctl" Enzo Matsumiya
                   ` (7 preceding siblings ...)
  2022-03-07  1:33 ` [PATCH 8/9] Unify all programs into a single binary "ksmbdctl" Enzo Matsumiya
@ 2022-03-07  1:33 ` Enzo Matsumiya
  2022-03-10  2:11 ` [PATCH 0/9] Unify all programs into a single binary "ksmbdctl" Namjae Jeon
  9 siblings, 0 replies; 13+ messages in thread
From: Enzo Matsumiya @ 2022-03-07  1:33 UTC (permalink / raw)
  To: linux-cifs, linkinjeon
  Cc: senozhatsky, sergey.senozhatsky, hyc.lee, smfrench, Enzo Matsumiya

Change README to markdown format.

Includes instructions for openSUSE.

Updates instructions for ksmbdctl (single binary).

Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
---
 README    | 100 ------------------------------------------------------
 README.md |  57 ++++++++++++++++---------------
 2 files changed, 30 insertions(+), 127 deletions(-)
 delete mode 100644 README

diff --git a/README b/README
deleted file mode 100644
index c64b75c58c2f..000000000000
--- a/README
+++ /dev/null
@@ -1,100 +0,0 @@
-________________________
-BUILDING KSMBD TOOLS
-________________________
-
-Install preprequisite packages:
-	For Ubuntu:
-	sudo apt-get install autoconf libtool pkg-config libnl-3-dev \
-	libnl-genl-3-dev libglib2.0-dev
-
-	For Fedora, RHEL:
-	sudo yum install autoconf automake libtool glib2-devel libnl3-devel
-
-	For CentOS:
-	sudo yum install glib2-devel libnl3-devel
-
-ksmbd-tools.spec should serve as a base template for RPM packagers.
-
-Build steps:
-        - cd into the ksmbd-tools directory
-        - ./autogen.sh
-        - ./configure
-        - make
-        - make install
-
-_____________________
-USING KSMBD TOOLS
-_____________________
-
-Setup steps:
-	- install smbd kernel driver
-		modprobe ksmbd
-	- create user/password for SMB share
-		mkdir /etc/ksmbd/
-		ksmbd.adduser -a <Enter USERNAME for SMB share access>
-		Enter password for SMB share access
-	- create /etc/ksmbd/smb.conf file, add SMB share in smb.conf file
-		Refer smb.conf.example
-	- start smbd user space daemon
-		ksmbd.mountd
-	- access share from Windows or Linux using CIFS
-
-_____________________
-RESTART KSMBD
-_____________________
-
-steps:
-	- kill user and kernel space daemon
-		sudo ksmbd.control -s
-	- restart user space daemon
-		ksmbd.mountd
-
-_____________________
-Shutdown KSMBD
-_____________________
-
-steps:
-	- kill user and kernel space daemon
-		sudo ksmbd.control -s
-	- unload ksmbd module
-		rmmod ksmbd
-
-
-_____________________
-Enable debug prints
-_____________________
-
-steps:
-	- Enable all component prints
-		sudo ksmbd.control -d "all"
-	- Enable one of components(smb, auth, vfs, oplock, ipc, conn, rdma)
-		sudo ksmbd.control -d "smb"
-	- Disable prints:
-		If you try the selected component once more, It is disabled without brackets.
-
-
---------------------
-ADMIN TOOLS
---------------------
-
-- ksmbd.adduser
-	Adds, updates or removes (-a/-u/-d) a user from ksmbd pwd file.
-
-- ksmbd.addshare
-	Adds, updates or removes (-a/-u/-d) a net share from smb.conf file.
-
-Usage example:
-
-Creating a new share:
-
-ksmbd.addshare -a files -o "\
-		     path=/home/users/files \
-		     comment=exported files \
-		     writeable=yes \
-		     read only = no \
-		     "
-
-Note that share options (-o) must always be enquoted ("...").
-
-ksmbd.addshare tool does not modify [global] smb.conf section; only net
-share configs are supported at the moment.
diff --git a/README.md b/README.md
index 7156c2e20dee..1e8fceb11e23 100644
--- a/README.md
+++ b/README.md
@@ -5,16 +5,17 @@
 ##### Install prerequisite packages:
 
 - For Ubuntu:
-  - `sudo apt-get install autoconf libtool pkg-config libnl-3-dev libnl-genl-3-dev libglib2.0-dev`
+  - `sudo apt-get install autoconf libtool pkg-config libnl-3-dev libnl-genl-3-dev libglib2.0-dev libkrb5-dev`
 
 - For Fedora, RHEL:
-  - `sudo yum install autoconf automake libtool glib2-devel libnl3-devel`
+  - `sudo yum install autoconf automake libtool glib2-devel libnl3-devel krb5-devel`
 
 - For CentOS:
-  - `sudo yum install glib2-devel libnl3-devel`
+  - `sudo yum install glib2-devel libnl3-devel krb5-devel`
 
 - For openSUSE:
-  - `sudo zypper install glib2-devel libnl3-devel`
+  - `sudo zypper install glib2-devel libnl3-devel krb5-devel`
+
 
 ##### Building:
 
@@ -32,31 +33,31 @@ All administration tasks must be done as root.
 
 ##### Setup:
 
-- Install ksmbd kernel driver
+- Install ksmbd kernel driver (requires CONFIG_SMB_SERVER=y)
 	- `modprobe ksmbd`
 - Create user/password for SMB share
 	- `mkdir /etc/ksmbd`
-	- `ksmbd.adduser -a <username>`
-	- Enter password for SMB share access
+	- `ksmbdctl user add <username>`
+	- Enter password for user when prompted
 - Create `/etc/ksmbd/smb.conf` file
 	- Refer `smb.conf.example`
 - Add share to `smb.conf`
-	- This can be done manually or with `ksmbd.addshare`, e.g.:
-	- `ksmbd.addshare -a myshare -o "guest ok = yes, writable = yes, path = /mnt/data"`
+	- This can be done either manually or with `ksmbdctl`, e.g.:
+	- `ksmbdctl share add myshare -o "guest ok = yes, writable = yes, path = /mnt/data"`
 
 	- Note: share options (-o) must always be enclosed with double quotes ("...").
 - Start ksmbd user space daemon
-	- `ksmbd.mountd`
-- Access share from Windows or Linux using CIFS
+	- `ksmbdctl daemon start`
+- Access share from Windows or Linux
 
 
 ##### Stopping and restarting the daemon:
 
-First, kill user and kernel space daemon
-  - `ksmbd.control -s`
+First, kill user and kernel space daemon:
+  - `ksmbdctl daemon shutdown`
 
 Then, to restart the daemon, run:
-  - `ksmbd.mountd`
+  - `ksmbdctl daemon start`
 
 Or to shut it down completely:
   - `rmmod ksmbd`
@@ -64,25 +65,27 @@ Or to shut it down completely:
 
 ### Debugging
 
-- Enable all component prints
-  - `ksmbd.control -d "all"`
-- Enable a single component (see below)
-  - `ksmbd.control -d "smb"`
-- Run the command with the same component name again to disable it
+- Enable debugging all components
+  - `ksmbdctl daemon debug "all"`
+- Enable debugging a single component (see more below)
+  - `ksmbdctl daemon debug "smb"`
+- Run the commands above with the same component name again to disable it
 
 Currently available debug components:
 smb, auth, vfs, oplock, ipc, conn, rdma
 
 
-### More...
+### User management
 
-- ksmbd.adduser
-  - Adds (-a), updates (-u), or deletes (-d) a user from user database.
-  - Default database file is `/etc/ksmbd/users.db`
+- ksmbdctl user
+  - Adds, updates, deletes, or lists users from database.
+  - Default database file is `/etc/ksmbd/users.db`, but can be changed with '-d'
+    option.
 
-- ksmbd.addshare
-  - Adds (-a), updates (-u), or deletes (-d) a net share from config file.
-  - Default config file is `/etc/ksmbd/smb.conf`
+- ksmbdctl share
+  - Adds, updates, deletes, or lists net shares from config file.
+  - Default config file is `/etc/ksmbd/smb.conf`, but can be changed with '-c'
+    option.
 
-`ksmbd.addshare` does not modify `[global]` section in config file; only net
+`ksmbdctl share add` does not modify `[global]` section in config file; only net
 share configs are supported at the moment.
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH 0/9] Unify all programs into a single binary "ksmbdctl"
  2022-03-07  1:33 [PATCH 0/9] Unify all programs into a single binary "ksmbdctl" Enzo Matsumiya
                   ` (8 preceding siblings ...)
  2022-03-07  1:33 ` [PATCH 9/9] README: change to markdown, updates for ksmbdctl Enzo Matsumiya
@ 2022-03-10  2:11 ` Namjae Jeon
  9 siblings, 0 replies; 13+ messages in thread
From: Namjae Jeon @ 2022-03-10  2:11 UTC (permalink / raw)
  To: Enzo Matsumiya
  Cc: linux-cifs, senozhatsky, sergey.senozhatsky, hyc.lee, smfrench

2022-03-07 10:33 GMT+09:00, Enzo Matsumiya <ematsumiya@suse.de>:
> Hello,
Hi Enzo,

First, Thanks for your work:)
>
> This commit unifies all existing programs
> (ksmbd.{adduser,addshare,control,mountd}) into a single ksmbdctl binary.
>
> The intention is to make it more like other modern tools (e.g. git,
> nvme, virsh, etc) which have more clear user interface, readable
> commands, and also makes it easier to script.
>
> Example commands:
>   # ksmbdctl share add myshare -o "guest ok=yes, writable=yes,
> path=/mnt/data"
>   # ksmbdctl user add myuser
>   # ksmbdctl user add -i $HOME/mysmb.conf anotheruser
>   # ksmbdctl daemon start
>
> Besides adding a new "share list" command, any previously working
> functionality shouldn't be affected.
>
> Basic testing was done manually.
>
> TODO:
> - run more complex tests in more complex environments
> - implement unit tests (for each command and subcommand)
If testcases are added to .travis.yml, It can be automatically tested
whenever a patch is applied.
> - create an abstract command interface, to make it easier to add/modify
>   commands
Could you please elaborate more what is abstract command interface ?

And totally looks good to me. Please run checkpatch.pl on these patches.

>
> Enzo Matsumiya (9):
>   ksmbd-tools: rename dirs to reflect new commands
>   ksmbd-tools: move control functions to daemon
>   ksmbd-tools: use quotes for local includes
>   share: introduce share_cmd
>   user: introduce user_cmd
>   daemon: introduce daemon_cmd
>   daemon/rpc_samr: drop unused function rpc_samr_remove_domain_entry()
>   Unify all programs into a single binary "ksmbdctl"
>   README: change to markdown, updates for ksmbdctl
>
>  Makefile.am                        |  14 +-
>  README                             | 100 -------
>  README.md                          |  57 ++--
>  addshare/addshare.c                | 172 -------------
>  addshare/share_admin.h             |  15 --
>  adduser/adduser.c                  | 180 -------------
>  adduser/user_admin.h               |  15 --
>  configure.ac                       |   7 +-
>  control/Makefile.am                |   7 -
>  control/control.c                  | 128 ---------
>  {mountd => daemon}/Makefile.am     |   2 +-
>  mountd/mountd.c => daemon/daemon.c | 401 +++++++++++++++++++++--------
>  daemon/daemon.h                    |  55 ++++
>  {mountd => daemon}/ipc.c           |  27 +-
>  {mountd => daemon}/rpc.c           |  21 +-
>  {mountd => daemon}/rpc_lsarpc.c    |  13 +-
>  {mountd => daemon}/rpc_samr.c      |  22 +-
>  {mountd => daemon}/rpc_srvsvc.c    |  11 +-
>  {mountd => daemon}/rpc_wkssvc.c    |  10 +-
>  {mountd => daemon}/smbacl.c        |   4 +-
>  {mountd => daemon}/worker.c        |  32 +--
>  include/config_parser.h            |   2 +-
>  include/ksmbdtools.h               |  24 +-
>  ksmbdctl.c                         | 182 +++++++++++++
>  lib/config_parser.c                |  15 +-
>  lib/ksmbdtools.c                   |  26 +-
>  lib/management/spnego.c            |   6 +-
>  lib/management/spnego_krb5.c       |   4 +-
>  {addshare => share}/Makefile.am    |   2 +-
>  share/share.c                      | 227 ++++++++++++++++
>  {addshare => share}/share_admin.c  |  97 +++++--
>  share/share_admin.h                |  44 ++++
>  {adduser => user}/Makefile.am      |   2 +-
>  {adduser => user}/md4_hash.c       |   2 +-
>  {adduser => user}/md4_hash.h       |   0
>  user/user.c                        | 238 +++++++++++++++++
>  {adduser => user}/user_admin.c     | 263 ++++++++++---------
>  user/user_admin.h                  |  44 ++++
>  38 files changed, 1458 insertions(+), 1013 deletions(-)
>  delete mode 100644 README
>  delete mode 100644 addshare/addshare.c
>  delete mode 100644 addshare/share_admin.h
>  delete mode 100644 adduser/adduser.c
>  delete mode 100644 adduser/user_admin.h
>  delete mode 100644 control/Makefile.am
>  delete mode 100644 control/control.c
>  rename {mountd => daemon}/Makefile.am (95%)
>  rename mountd/mountd.c => daemon/daemon.c (55%)
>  create mode 100644 daemon/daemon.h
>  rename {mountd => daemon}/ipc.c (95%)
>  rename {mountd => daemon}/rpc.c (98%)
>  rename {mountd => daemon}/rpc_lsarpc.c (98%)
>  rename {mountd => daemon}/rpc_samr.c (98%)
>  rename {mountd => daemon}/rpc_srvsvc.c (98%)
>  rename {mountd => daemon}/rpc_wkssvc.c (97%)
>  rename {mountd => daemon}/smbacl.c (99%)
>  rename {mountd => daemon}/worker.c (95%)
>  create mode 100644 ksmbdctl.c
>  rename {addshare => share}/Makefile.am (74%)
>  create mode 100644 share/share.c
>  rename {addshare => share}/share_admin.c (68%)
>  create mode 100644 share/share_admin.h
>  rename {adduser => user}/Makefile.am (69%)
>  rename {adduser => user}/md4_hash.c (99%)
>  rename {adduser => user}/md4_hash.h (100%)
>  create mode 100644 user/user.c
>  rename {adduser => user}/user_admin.c (52%)
>  create mode 100644 user/user_admin.h
>
> --
> 2.34.1
>
>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 5/9] user: introduce user_cmd
  2022-03-07  1:33 ` [PATCH 5/9] user: introduce user_cmd Enzo Matsumiya
@ 2022-03-10  2:17   ` Namjae Jeon
  0 siblings, 0 replies; 13+ messages in thread
From: Namjae Jeon @ 2022-03-10  2:17 UTC (permalink / raw)
  To: Enzo Matsumiya
  Cc: linux-cifs, senozhatsky, sergey.senozhatsky, hyc.lee, smfrench

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
>
>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 4/9] share: introduce share_cmd
  2022-03-07  1:33 ` [PATCH 4/9] share: introduce share_cmd Enzo Matsumiya
@ 2022-03-10  2:19   ` Namjae Jeon
  0 siblings, 0 replies; 13+ messages in thread
From: Namjae Jeon @ 2022-03-10  2:19 UTC (permalink / raw)
  To: Enzo Matsumiya
  Cc: linux-cifs, senozhatsky, sergey.senozhatsky, hyc.lee, smfrench

2022-03-07 10:33 GMT+09:00, Enzo Matsumiya <ematsumiya@suse.de>:
> Create share command in preparation for binary unification.
>
> Introduce a command to list available shares.
>
> Makes open_smbconf() optionally truncate the file (for list command).
>
> Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
> ---
>  include/ksmbdtools.h |  16 ++-
>  share/Makefile.am    |   2 +-
>  share/addshare.c     | 172 --------------------------------
>  share/share.c        | 227 +++++++++++++++++++++++++++++++++++++++++++
>  share/share_admin.c  |  85 ++++++++++++----
>  share/share_admin.h  |  35 ++++++-
>  6 files changed, 335 insertions(+), 202 deletions(-)
>  delete mode 100644 share/addshare.c
>  create mode 100644 share/share.c
>
> diff --git a/include/ksmbdtools.h b/include/ksmbdtools.h
> index 170ce23ead2c..fccb88d8898a 100644
> --- a/include/ksmbdtools.h
> +++ b/include/ksmbdtools.h
> @@ -101,12 +101,14 @@ extern int ksmbd_health_status;
>  //---------------------------------------------------------------//
>  #define LOGAPP		"[%s/%d]:"
>  #define PRERR		LOGAPP" ERROR: "
> +#define PRWARN		LOGAPP" WARN: "
>  #define PRINF		LOGAPP" INFO: "
>  #define PRDEBUG		LOGAPP" DEBUG: "
>
>  #define PR_ERROR	0
> -#define PR_INFO		1
> -#define PR_DEBUG	2
> +#define PR_WARN		1
> +#define PR_INFO		2
> +#define PR_DEBUG	3
>
>  static int log_level = PR_INFO;
>
> @@ -134,12 +136,16 @@ extern void pr_logger_init(int flags);
>  					##__VA_ARGS__);			\
>  	} while (0)
>
> -#define pr_debug(f, ...)	\
> +#define pr_debug(f, ...) \
>  	pr_log(PR_DEBUG, PRDEBUG f, ##__VA_ARGS__)
> -#define pr_info(f, ...)	\
> +#define pr_info(f, ...) \
>  	pr_log(PR_INFO, PRINF f, ##__VA_ARGS__)
> -#define pr_err(f, ...)	\
> +#define pr_warn(f, ...) \
> +	pr_log(PR_WARN, PRWARN f, ##__VA_ARGS__)
> +#define pr_err(f, ...) \
>  	pr_log(PR_ERROR, PRERR f, ##__VA_ARGS__)
> +#define pr_out(f, ...) \
> +	fprintf(stderr, f, ##__VA_ARGS__)
>
>  //---------------------------------------------------------------//
>
> diff --git a/share/Makefile.am b/share/Makefile.am
> index dafc985add5d..bea487edfeeb 100644
> --- a/share/Makefile.am
> +++ b/share/Makefile.am
> @@ -4,4 +4,4 @@ ksmbd_addshare_LDADD = $(top_builddir)/lib/libksmbdtools.a
>
>  sbin_PROGRAMS = ksmbd.addshare
>
> -ksmbd_addshare_SOURCES = share_admin.c addshare.c share_admin.h
> +ksmbd_addshare_SOURCES = share_admin.c share.c share_admin.h
> diff --git a/share/addshare.c b/share/addshare.c
> deleted file mode 100644
> index 4ff94b18a641..000000000000
> --- a/share/addshare.c
> +++ /dev/null
> @@ -1,172 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0-or-later
> -/*
> - *   Copyright (C) 2019 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/share.h"
> -#include "linux/ksmbd_server.h"
> -#include "share_admin.h"
> -#include "version.h"
> -
> -static char *arg_name;
> -static char *arg_opts;
> -
> -enum {
> -	COMMAND_ADD_SHARE = 1,
> -	COMMAND_DEL_SHARE,
> -	COMMAND_UPDATE_SHARE,
> -};
> -
> -static void usage(void)
> -{
> -	int i;
> -
> -	fprintf(stderr, "Usage: smbshareadd\n");
> -
> -	fprintf(stderr, "\t-a | --add-share=share\n");
> -	fprintf(stderr, "\t-d | --del-share=share\n");
> -	fprintf(stderr, "\t-u | --update-share=share\n");
> -	fprintf(stderr, "\t-o | --options=\"op1=val1 op2=val2...\"\n");
> -
> -	fprintf(stderr, "\t-c smb.conf\n");
> -	fprintf(stderr, "\t-V | --version\n");
> -	fprintf(stderr, "\t-v | --verbose\n");
> -
> -	fprintf(stderr, "Supported share options:\n");
> -	for (i = 0; i < KSMBD_SHARE_CONF_MAX; i++)
> -		fprintf(stderr, "\t%s\n", KSMBD_SHARE_CONF[i]);
> -	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 *smbconf)
> -{
> -	int ret;
> -
> -	ret = test_file_access(smbconf);
> -	if (ret)
> -		return ret;
> -
> -	ret = cp_smbconfig_hash_create(smbconf);
> -	if (ret)
> -		return ret;
> -	return 0;
> -}
> -
> -static int sanity_check_share_name_simple(char *name)
> -{
> -	int sz, i;
> -
> -	if (!name)
> -		return -EINVAL;
> -
> -	sz = strlen(name);
> -	if (sz < 1)
> -		return -EINVAL;
> -	if (sz >= KSMBD_REQ_MAX_SHARE_NAME)
> -		return -EINVAL;
> -
> -	if (!cp_key_cmp(name, "global"))
> -		return -EINVAL;
> -
> -	return -EINVAL;
> -}
> -
> -int main(int argc, char *argv[])
> -{
> -	int ret = EXIT_FAILURE;
> -	char *smbconf = PATH_SMBCONF;
> -	int c, cmd = 0;
> -
> -	set_logger_app_name("ksmbd.addshare");
> -
> -	opterr = 0;
> -	while ((c = getopt(argc, argv, "c:a:d:u:p:o:Vvh")) != EOF)
> -		switch (c) {
> -		case 'a':
> -			arg_name = g_ascii_strdown(optarg, strlen(optarg));
> -			cmd = COMMAND_ADD_SHARE;
> -			break;
> -		case 'd':
> -			arg_name = g_ascii_strdown(optarg, strlen(optarg));
> -			cmd = COMMAND_DEL_SHARE;
> -			break;
> -		case 'u':
> -			arg_name = g_ascii_strdown(optarg, strlen(optarg));
> -			cmd = COMMAND_UPDATE_SHARE;
> -			break;
> -		case 'c':
> -			smbconf = strdup(optarg);
> -			break;
> -		case 'o':
> -			arg_opts = strdup(optarg);
> -			break;
> -		case 'V':
> -			show_version();
> -			break;
> -		case 'v':
> -			break;
> -		case '?':
> -		case 'h':
> -		default:
> -			usage();
> -	}
> -
> -	if (cmd != COMMAND_DEL_SHARE && !arg_opts) {
> -		usage();
> -		return -1;
> -	}
> -
> -	if (sanity_check_share_name_simple(arg_name)) {
> -		pr_err("share name sanity check failure\n");
> -		goto out;
> -	}
> -
> -	if (!smbconf) {
> -		pr_err("Out of memory\n");
> -		goto out;
> -	}
> -
> -	ret = parse_configs(smbconf);
> -	if (ret) {
> -		pr_err("Unable to parse configuration files\n");
> -		goto out;
> -	}
> -
> -	if (cmd == COMMAND_ADD_SHARE)
> -		ret = command_add_share(smbconf, arg_name, arg_opts);
> -	if (cmd == COMMAND_DEL_SHARE)
> -		ret = command_del_share(smbconf, arg_name);
> -	if (cmd == COMMAND_UPDATE_SHARE)
> -		ret = command_update_share(smbconf, arg_name, arg_opts);
> -
> -	/*
> -	 * We support only ADD_SHARE command for the time being
> -	 */
> -	if (ret == 0 && cmd == COMMAND_ADD_SHARE)
> -		notify_ksmbd_daemon();
> -out:
> -	cp_smbconfig_destroy();
> -	return ret;
> -}
> diff --git a/share/share.c b/share/share.c
> new file mode 100644
> index 000000000000..91d23d28c426
> --- /dev/null
> +++ b/share/share.c
> @@ -0,0 +1,227 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + *   Copyright (C) 2019 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/share.h"
> +#include "linux/ksmbd_server.h"
> +#include "share_admin.h"
> +
> +static ksmbd_share_cmd ksmbd_share_get_cmd(char *cmd)
> +{
> +	int i;
> +
> +	if (!cmd)
> +		return KSMBD_CMD_SHARE_NONE;
> +
> +	for (i = 1; i < KSMBD_CMD_SHARE_MAX; i++)
> +		if (!strcmp(cmd, ksmbd_share_cmds_str[i]))
> +			return (ksmbd_share_cmd)i;
> +
> +	return KSMBD_CMD_SHARE_NONE;
> +}
> +
> +static const char *ksmbd_share_get_cmd_str(ksmbd_share_cmd cmd)
> +{
> +	if (cmd > KSMBD_CMD_SHARE_MAX)
> +		return ksmbd_share_cmds_str[KSMBD_CMD_SHARE_NONE];
> +
> +	return ksmbd_share_cmds_str[(int)cmd];
> +}
> +
> +static int parse_configs(char *smbconf)
> +{
> +	int ret;
> +
> +	ret = test_file_access(smbconf);
> +	if (ret)
> +		return ret;
> +
> +	ret = cp_smbconfig_hash_create(smbconf);
> +	if (ret)
> +		return ret;
> +	return 0;
> +}
> +
> +static int sanity_check_share_name_simple(char *name)
> +{
> +	int sz, i;
> +
> +	if (!name)
> +		return -EINVAL;
> +
> +	sz = strlen(name);
> +	if (sz < 1)
> +		return -EINVAL;
> +	if (sz >= KSMBD_REQ_MAX_SHARE_NAME)
> +		return -EINVAL;
> +
> +	if (!cp_key_cmp(name, "global"))
> +		return -EINVAL;
> +
> +	for (i = 0; i < sz; i++) {
> +		if (isalnum(name[i]))
This check was removed before. Please remove this.

Thanks.
> +			return 0;
> +	}
> +	return -EINVAL;
> +}
> +
> +void share_usage(ksmbd_share_cmd cmd)
> +{
> +	int i;
> +	const char *cmd_str = ksmbd_share_get_cmd_str(cmd);
> +
> +	switch (cmd) {
> +	case KSMBD_CMD_SHARE_ADD:
> +	case KSMBD_CMD_SHARE_UPDATE:
> +		pr_out("Usage: ksmbdctl share %s <share_name> [-c <file>] -o
> \"op1=val1,op2=val2,...\"\n", cmd_str);
> +		pr_out("Adds or updates a share to smb.conf file.\n\n");
> +		pr_out("%-30s%s", "  -c, --conf=<file>", "Use <file> as smb.conf\n");
> +		pr_out("%-30s%s", "  -o, --options=<options>", "Specify options for
> share\n\n");
> +		pr_out("Supported share options:\n");
> +		for (i = 0; i < KSMBD_SHARE_CONF_MAX; i++)
> +			pr_out("%s\n", KSMBD_SHARE_CONF[i]);
> +		break;
> +	case KSMBD_CMD_SHARE_DELETE:
> +		pr_out("Usage: ksmbdctl share delete <share_name>\n");
> +		pr_out("Deletes a share.\n\n");
> +		break;
> +	default:
> +		pr_out("Usage: ksmbdctl share <subcommand> <args> [options]\n");
> +		pr_out("Share management.\n\n");
> +		pr_out("List of available subcommands:\n");
> +		pr_out("%-20s%s", "  add", "Add a share\n");
> +		pr_out("%-20s%s", "  delete", "Delete a share\n");
> +		pr_out("%-20s%s", "  update", "Update a share\n");
> +		pr_out("%-20s%s", "  list", "List the names of all shares
> available\n\n");
> +		break;
> +	}
> +
> +	exit(EXIT_FAILURE);
> +}
> +
> +int share_cmd(int argc, char *argv[])
> +{
> +	int ret = EXIT_FAILURE;
> +	char *smbconf = PATH_SMBCONF;
> +	char *share_name = NULL;
> +	char *options = NULL;
> +	ksmbd_share_cmd cmd = KSMBD_CMD_SHARE_NONE;
> +	int c;
> +
> +	if (argc < 2)
> +		goto usage;
> +
> +	set_logger_app_name("ksmbd-share");
> +
> +	cmd = ksmbd_share_get_cmd(argv[1]);
> +
> +	if (cmd == KSMBD_CMD_SHARE_NONE)
> +		goto usage;
> +
> +	if(argc == 2 && cmd != KSMBD_CMD_SHARE_LIST)
> +		goto missing_arg;
> +
> +	if (argv[2] && argv[2][0] != '-')
> +		share_name = g_ascii_strdown(argv[2], strlen(argv[2]));
> +	else if (cmd != KSMBD_CMD_SHARE_LIST)
> +		goto usage;
> +
> +	optind = 1;
> +	while ((c = getopt_long(argc, argv, "-:c:o:", share_opts, NULL)) != EOF)
> +		switch (c) {
> +		case 1:
> +			break;
> +		case 'c':
> +			if (cmd == KSMBD_CMD_SHARE_DELETE)
> +				continue;
> +			smbconf = strdup(optarg);
> +			break;
> +		case 'o':
> +			if (cmd == KSMBD_CMD_SHARE_DELETE || cmd == KSMBD_CMD_SHARE_LIST)
> +				continue;
> +			options = strdup(optarg);
> +			break;
> +		case ':':
> +		case '?':
> +		default:
> +			goto usage;
> +		}
> +
> +	if (cmd == KSMBD_CMD_SHARE_LIST)
> +		goto share_list;
> +
> +	if (!share_name)
> +		goto missing_arg;
> +
> +	if (cmd != KSMBD_CMD_SHARE_DELETE && !options) {
> +		pr_out("Subcommand \"%s\" requires '-o' option set.\n\n",
> ksmbd_share_get_cmd_str(cmd));
> +		goto usage;
> +	}
> +
> +	if (sanity_check_share_name_simple(share_name)) {
> +		pr_err("Share name (%s) sanity check failure\n", share_name);
> +		goto out;
> +	}
> +
> +share_list:
> +	if (!smbconf) {
> +		pr_err("Out of memory\n");
> +		goto out;
> +	}
> +
> +	ret = parse_configs(smbconf);
> +	if (ret) {
> +		pr_err("Unable to parse configuration file %s\n", smbconf);
> +		goto out;
> +	}
> +
> +	switch (cmd) {
> +	case KSMBD_CMD_SHARE_ADD:
> +		ret = share_add_cmd(smbconf, share_name, options);
> +		break;
> +	case KSMBD_CMD_SHARE_DELETE:
> +		ret = share_delete_cmd(smbconf, share_name);
> +		break;
> +	case KSMBD_CMD_SHARE_UPDATE:
> +		ret = share_update_cmd(smbconf, share_name, options);
> +		break;
> +	case KSMBD_CMD_SHARE_LIST:
> +		ret = share_list_cmd(smbconf);
> +		break;
> +	}
> +
> +	/*
> +	 * FIXME: We support only ADD_SHARE command for the time being
> +	 */
> +	if (ret == 0 && cmd == KSMBD_CMD_SHARE_ADD)
> +		notify_ksmbd_daemon();
> +
> +out:
> +	cp_smbconfig_destroy();
> +	return ret;
> +missing_arg:
> +	if (cmd > KSMBD_CMD_SHARE_NONE && cmd < KSMBD_CMD_SHARE_MAX)
> +		pr_out("Subcommand \"%s\" requires an argument.\n\n",
> ksmbd_share_get_cmd_str(cmd));
> +usage:
> +	share_usage(cmd);
> +
> +	return ret;
> +}
> diff --git a/share/share_admin.c b/share/share_admin.c
> index 0ff13d8017dd..61780fb00b5a 100644
> --- a/share/share_admin.c
> +++ b/share/share_admin.c
> @@ -1,12 +1,14 @@
>  // SPDX-License-Identifier: GPL-2.0-or-later
>  /*
>   *   Copyright (C) 2019 Samsung Electronics Co., Ltd.
> + *   Copyright (C) 2021 SUSE LLC
>   *
>   *   linux-cifsd-devel@lists.sourceforge.net
>   */
>
>  #include <glib.h>
>  #include <stdlib.h>
> +#include <stdbool.h>
>  #include <stdio.h>
>  #include <unistd.h>
>  #include <getopt.h>
> @@ -48,24 +50,26 @@ static char *aux_group_name(char *name)
>  	return gn;
>  }
>
> -static int __open_smbconf(char *smbconf)
> +static int open_smbconf(char *smbconf, bool truncate)
>  {
> -	conf_fd = open(smbconf, O_WRONLY);
> +	conf_fd = open(smbconf, O_RDWR);
>  	if (conf_fd == -1) {
>  		pr_err("%s %s\n", strerr(errno), smbconf);
>  		return -EINVAL;
>  	}
>
> -	if (ftruncate(conf_fd, 0)) {
> -		pr_err("%s %s\n", strerr(errno), smbconf);
> -		close(conf_fd);
> -		return -EINVAL;
> +	if (truncate) {
> +		if (ftruncate(conf_fd, 0)) {
> +			pr_err("%s %s\n", strerr(errno), smbconf);
> +			close(conf_fd);
> +			return -EINVAL;
> +		}
>  	}
>
>  	return 0;
>  }
>
> -static void __write(void)
> +static void do_write(void)
>  {
>  	int nr = 0;
>  	int ret;
> @@ -83,7 +87,7 @@ static void __write(void)
>  	}
>  }
>
> -static void __write_share(gpointer key, gpointer value, gpointer buf)
> +static void write_share(gpointer key, gpointer value, gpointer buf)
>  {
>  	char *k = (char *)key;
>  	char *v = (char *)value;
> @@ -95,14 +99,14 @@ static void __write_share(gpointer key, gpointer value,
> gpointer buf)
>  			sizeof(wbuf));
>  		exit(EXIT_FAILURE);
>  	}
> -	__write();
> +	do_write();
>  }
>
> -static void write_share(struct smbconf_group *g)
> +static void write_share_all(struct smbconf_group *g)
>  {
>  	wsz = snprintf(wbuf, sizeof(wbuf), "[%s]\n", g->name);
> -	__write();
> -	g_hash_table_foreach(g->kv, __write_share, NULL);
> +	do_write();
> +	g_hash_table_foreach(g->kv, write_share, NULL);
>  }
>
>  static void write_share_cb(gpointer key, gpointer value, gpointer
> share_data)
> @@ -113,7 +117,7 @@ static void write_share_cb(gpointer key, gpointer value,
> gpointer share_data)
>  	 * Do not write AUX group
>  	 */
>  	if (!strstr(g->name, AUX_GROUP_PREFIX))
> -		write_share(g);
> +		write_share_all(g);
>  }
>
>  static void write_remove_share_cb(gpointer key,
> @@ -127,7 +131,7 @@ static void write_remove_share_cb(gpointer key,
>  		return;
>  	}
>
> -	write_share(g);
> +	write_share_all(g);
>  }
>
>  static void update_share_cb(gpointer key,
> @@ -145,12 +149,32 @@ static void update_share_cb(gpointer key,
>  	g_hash_table_insert(g, nk, nv);
>  }
>
> -int command_add_share(char *smbconf, char *name, char *opts)
> +static void list_shares_cb(gpointer key, gpointer value, gpointer data)
> +{
> +	char *nk, *nv;
> +
> +	nk = g_strdup(key);
> +	nv = g_strdup(value);
> +
> +	if (!nk || !nv)
> +		exit(EXIT_FAILURE);
> +
> +	if (!strcmp(nk, "global"))
> +		goto out;
> +
> +	pr_out("%s\n", nk);
> +
> +out:
> +	g_free(nk);
> +	g_free(nv);
> +}
> +
> +int share_add_cmd(char *smbconf, char *name, char *opts)
>  {
>  	char *new_name = NULL;
>
>  	if (g_hash_table_lookup(parser.groups, name)) {
> -		pr_err("Share already exists: %s\n", name);
> +		pr_warn("Share already exists: %s\n", name);
>  		return -EEXIST;
>  	}
>
> @@ -158,7 +182,7 @@ int command_add_share(char *smbconf, char *name, char
> *opts)
>  	if (cp_parse_external_smbconf_group(new_name, opts))
>  		goto error;
>
> -	if (__open_smbconf(smbconf))
> +	if (open_smbconf(smbconf, true))
>  		goto error;
>  	g_hash_table_foreach(parser.groups, write_share_cb, NULL);
>  	close(conf_fd);
> @@ -170,7 +194,7 @@ error:
>  	return -EINVAL;
>  }
>
> -int command_update_share(char *smbconf, char *name, char *opts)
> +int share_update_cmd(char *smbconf, char *name, char *opts)
>  {
>  	struct smbconf_group *existing_group;
>  	struct smbconf_group *update_group;
> @@ -198,7 +222,7 @@ int command_update_share(char *smbconf, char *name, char
> *opts)
>  			     update_share_cb,
>  			     existing_group->kv);
>
> -	if (__open_smbconf(smbconf))
> +	if (open_smbconf(smbconf, true))
>  		goto error;
>
>  	g_hash_table_foreach(parser.groups, write_share_cb, NULL);
> @@ -211,9 +235,9 @@ error:
>  	return -EINVAL;
>  }
>
> -int command_del_share(char *smbconf, char *name)
> +int share_delete_cmd(char *smbconf, char *name)
>  {
> -	if (__open_smbconf(smbconf))
> +	if (open_smbconf(smbconf, true))
>  		return -EINVAL;
>
>  	g_hash_table_foreach(parser.groups,
> @@ -222,3 +246,22 @@ int command_del_share(char *smbconf, char *name)
>  	close(conf_fd);
>  	return 0;
>  }
> +
> +int share_list_cmd(char *smbconf)
> +{
> +	if (open_smbconf(smbconf, false))
> +		return -EINVAL;
> +
> +	if (g_hash_table_size(parser.groups) <= 1) {
> +		pr_out("No shares available in %s.\n", smbconf);
> +		goto out;
> +	}
> +
> +	pr_out("Shares available in %s:\n", smbconf);
> +	g_hash_table_foreach(parser.groups,
> +			     list_shares_cb,
> +			     NULL);
> +out:
> +	close(conf_fd);
> +	return 0;
> +}
> diff --git a/share/share_admin.h b/share/share_admin.h
> index 7df3871bfe81..00cf1147af18 100644
> --- a/share/share_admin.h
> +++ b/share/share_admin.h
> @@ -1,6 +1,7 @@
>  /* SPDX-License-Identifier: GPL-2.0-or-later */
>  /*
>   *   Copyright (C) 2019 Samsung Electronics Co., Ltd.
> + *   Copyright (C) 2021 SUSE LLC
>   *
>   *   linux-cifsd-devel@lists.sourceforge.net
>   */
> @@ -8,8 +9,36 @@
>  #ifndef __KSMBD_SHARE_ADMIN_H__
>  #define __KSMBD_SHARE_ADMIN_H__
>
> -int command_add_share(char *smbconf, char *name, char *opts);
> -int command_update_share(char *smbconf, char *name, char *opts);
> -int command_del_share(char *smbconf, char *name);
> +int share_add_cmd(char *smbconf, char *name, char *opts);
> +int share_delete_cmd(char *smbconf, char *name);
> +int share_update_cmd(char *smbconf, char *name, char *opts);
> +int share_list_cmd(char *smbconf);
> +
> +typedef enum {
> +	KSMBD_CMD_SHARE_NONE = 0,
> +	KSMBD_CMD_SHARE_ADD,
> +	KSMBD_CMD_SHARE_DELETE,
> +	KSMBD_CMD_SHARE_UPDATE,
> +	KSMBD_CMD_SHARE_LIST,
> +	KSMBD_CMD_SHARE_MAX
> +} ksmbd_share_cmd;
> +
> +/* List of supported subcommands */
> +static const char *ksmbd_share_cmds_str[] = {
> +	"none",
> +	"add",
> +	"delete",
> +	"update",
> +	"list"
> +};
> +
> +static struct option share_opts[] = {
> +        { "conf", required_argument, NULL, 'c' },
> +        { "options", required_argument, NULL, 'o' },
> +	{ 0, 0, 0, 0 },
> +};
> +
> +void share_usage(ksmbd_share_cmd cmd);
> +int share_cmd(int argc, char *argv[]);
>
>  #endif /* __KSMBD_SHARE_ADMIN_H__ */
> --
> 2.34.1
>
>

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2022-03-10  2:19 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-07  1:33 [PATCH 0/9] Unify all programs into a single binary "ksmbdctl" Enzo Matsumiya
2022-03-07  1:33 ` [PATCH 1/9] ksmbd-tools: rename dirs to reflect new commands Enzo Matsumiya
2022-03-07  1:33 ` [PATCH 2/9] ksmbd-tools: move control functions to daemon Enzo Matsumiya
2022-03-07  1:33 ` [PATCH 3/9] ksmbd-tools: use quotes for local includes Enzo Matsumiya
2022-03-07  1:33 ` [PATCH 4/9] share: introduce share_cmd Enzo Matsumiya
2022-03-10  2:19   ` Namjae Jeon
2022-03-07  1:33 ` [PATCH 5/9] user: introduce user_cmd Enzo Matsumiya
2022-03-10  2:17   ` Namjae Jeon
2022-03-07  1:33 ` [PATCH 6/9] daemon: introduce daemon_cmd Enzo Matsumiya
2022-03-07  1:33 ` [PATCH 7/9] daemon/rpc_samr: drop unused function rpc_samr_remove_domain_entry() Enzo Matsumiya
2022-03-07  1:33 ` [PATCH 8/9] Unify all programs into a single binary "ksmbdctl" Enzo Matsumiya
2022-03-07  1:33 ` [PATCH 9/9] README: change to markdown, updates for ksmbdctl Enzo Matsumiya
2022-03-10  2:11 ` [PATCH 0/9] Unify all programs into a single binary "ksmbdctl" Namjae Jeon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).