+++ /dev/null
-From 6b74583bd62e2b6ed6b76ff72d8fc7c2d8f26510 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Atte=20Heikkil=C3=A4?= <atteh.mailbox@gmail.com>
-Date: Thu, 13 Oct 2022 20:08:47 +0300
-Subject: [PATCH] ksmbd-tools: build utilities as a single binary
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Rather than have four different binaries, i.e. ksmbd.addshare,
-ksmbd.adduser, ksmbd.control, and ksmbd.mountd, each one including
-its own libksmbdtools.a copy, build them instead as a single binary.
-This resulting ksmbd.tools acts like BusyBox in that its behavior
-depends on the name by which it is called. Then, each utility is made
-into a symlink to it, meaning that users keep using the utilities as
-usual. ksmbd.tools itself is installed to libexecdir as it is not
-something the user should run.
-
-Instead of libksmbdtools.a, each utility becomes its own static
-library, i.e. libaddshare.a, libadduser.a, libcontrol.a, libmountd.a,
-which are all linked to the single binary. Note that the single binary
-approach is also beneficial when statically linking to any of the
-external dependencies, e.g. GLib, as it greatly reduces the overall
-binary size when there is overlap in copies otherwise made separately
-for multiple utilities.
-
-Due to install_symlink(), minimum meson version is bumped to 0.62.1,
-meaning that it has to be installed using `pip' in Travis, since no
-Ubuntu release currently packages that version or newer. However, bump
-to Ubuntu Jammy anyways, just for the sake of building against newer
-versions of ksmbd-tools' dependencies.
-
-Signed-off-by: Atte Heikkilä <atteh.mailbox@gmail.com>
----
- .travis.yml | 6 ++++--
- Makefile.am | 2 +-
- addshare/Makefile.am | 15 ++++++++-----
- addshare/addshare.c | 4 ++--
- addshare/meson.build | 22 ++++++++++---------
- addshare/share_admin.c | 2 +-
- adduser/Makefile.am | 16 ++++++++------
- adduser/adduser.c | 4 ++--
- adduser/meson.build | 22 ++++++++++---------
- adduser/user_admin.c | 2 +-
- configure.ac | 8 ++++---
- control/Makefile.am | 15 ++++++++-----
- control/control.c | 4 ++--
- control/meson.build | 22 ++++++++++---------
- include/{ksmbdtools.h => tools.h} | 11 +++++++---
- ksmbd-tools.spec | 3 ++-
- meson.build | 6 +++---
- mountd/Makefile.am | 17 +++++++++------
- mountd/ipc.c | 2 +-
- mountd/meson.build | 23 +++++++++++---------
- mountd/mountd.c | 4 ++--
- mountd/rpc.c | 2 +-
- mountd/rpc_lsarpc.c | 2 +-
- mountd/rpc_samr.c | 2 +-
- mountd/rpc_srvsvc.c | 2 +-
- mountd/rpc_wkssvc.c | 2 +-
- mountd/smbacl.c | 2 +-
- mountd/worker.c | 2 +-
- {lib => tools}/Makefile.am | 15 +++++++------
- {lib => tools}/asn1.c | 0
- {lib => tools}/config_parser.c | 2 +-
- {lib => tools}/management/session.c | 2 +-
- {lib => tools}/management/share.c | 2 +-
- {lib => tools}/management/spnego.c | 2 +-
- {lib => tools}/management/spnego_krb5.c | 2 +-
- {lib => tools}/management/spnego_mech.h | 0
- {lib => tools}/management/tree_conn.c | 2 +-
- {lib => tools}/management/user.c | 2 +-
- {lib => tools}/meson.build | 28 ++++++++++++++++---------
- lib/ksmbdtools.c => tools/tools.c | 27 +++++++++++++++++++++++-
- 40 files changed, 191 insertions(+), 117 deletions(-)
- rename include/{ksmbdtools.h => tools.h} (94%)
- rename {lib => tools}/Makefile.am (53%)
- rename {lib => tools}/asn1.c (100%)
- rename {lib => tools}/config_parser.c (99%)
- rename {lib => tools}/management/session.c (99%)
- rename {lib => tools}/management/share.c (99%)
- rename {lib => tools}/management/spnego.c (99%)
- rename {lib => tools}/management/spnego_krb5.c (99%)
- rename {lib => tools}/management/spnego_mech.h (100%)
- rename {lib => tools}/management/tree_conn.c (99%)
- rename {lib => tools}/management/user.c (99%)
- rename {lib => tools}/meson.build (60%)
- rename lib/ksmbdtools.c => tools/tools.c (89%)
-
---- a/.travis.yml
-+++ b/.travis.yml
-@@ -1,4 +1,4 @@
--dist: focal
-+dist: jammy
-
- language: c
-
-@@ -6,9 +6,11 @@ notifications:
- - email: true
-
- before_install:
-- - sudo apt-get install libnl-3-dev libnl-genl-3-dev krb5-multidev heimdal-multidev meson
-+ - sudo apt-get install libnl-3-dev libnl-genl-3-dev krb5-multidev heimdal-multidev ninja-build
- - gcc --version
- - g++ --version
-+ - pip3 install --user meson
-+ - PATH=$HOME/.local/bin:$PATH
-
- jobs:
- include:
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -1,6 +1,6 @@
- ACLOCAL_AMFLAGS = -I m4
-
--SUBDIRS = lib mountd adduser addshare control
-+SUBDIRS = addshare adduser control mountd tools
-
- EXTRA_DIST = include \
- README.md \
---- a/addshare/Makefile.am
-+++ b/addshare/Makefile.am
-@@ -1,11 +1,8 @@
- AM_CFLAGS = -DSYSCONFDIR='"${sysconfdir}"' -DRUNSTATEDIR='"${runstatedir}"' \
- -I$(top_srcdir)/include $(GLIB_CFLAGS) $(LIBNL_CFLAGS) -fno-common
--LIBS = $(GLIB_LIBS)
--ksmbd_addshare_LDADD = $(top_builddir)/lib/libksmbdtools.a
-
--sbin_PROGRAMS = ksmbd.addshare
--
--ksmbd_addshare_SOURCES = share_admin.c addshare.c share_admin.h
-+noinst_LIBRARIES = libaddshare.a
-+libaddshare_a_SOURCES = share_admin.c addshare.c share_admin.h
-
- EXTRA_DIST = ksmbd.addshare.8.in
-
-@@ -13,3 +10,11 @@ man_MANS = ksmbd.addshare.8
- $(man_MANS): %: %.in; @$(in_script) $< >$@
-
- CLEANFILES = $(man_MANS)
-+
-+install-exec-hook: uninstall-hook
-+ $(MKDIR_P) $(DESTDIR)$(sbindir)
-+ ( cd $(DESTDIR)$(sbindir) && \
-+ $(LN_S) $(libexecdir)/ksmbd.tools ksmbd.addshare )
-+
-+uninstall-hook:
-+ -rm $(DESTDIR)$(sbindir)/ksmbd.addshare
---- a/addshare/addshare.c
-+++ b/addshare/addshare.c
-@@ -18,7 +18,7 @@
- #include <ctype.h>
-
- #include "config_parser.h"
--#include "ksmbdtools.h"
-+#include "tools.h"
- #include "management/share.h"
- #include "linux/ksmbd_server.h"
- #include "share_admin.h"
-@@ -111,7 +111,7 @@ static int sanity_check_share_name_simpl
- return 0;
- }
-
--int main(int argc, char *argv[])
-+int addshare_main(int argc, char **argv)
- {
- int ret = -EINVAL;
- char *share = NULL, *options = NULL, *smbconf = NULL;
---- a/addshare/meson.build
-+++ b/addshare/meson.build
-@@ -1,20 +1,16 @@
--executable(
-- 'ksmbd.addshare',
-+addshare_lib = static_library(
-+ 'addshare',
- 'share_admin.c',
- 'addshare.c',
- 'share_admin.h',
-- dependencies: [
-- glib_dep,
-- libnl_dep,
-- ],
-- include_directories: tools_incdir,
-- link_with: libksmbdtools,
-- install: true,
-- install_dir: get_option('sbindir'),
-+ include_directories: include_dirs,
- c_args: [
- '-DSYSCONFDIR="@0@"'.format(get_option('prefix') / get_option('sysconfdir')),
- '-DRUNSTATEDIR="@0@"'.format(runstatedir),
- ],
-+ dependencies: [
-+ glib_dep,
-+ ],
- )
-
- configure_file(
-@@ -23,3 +19,9 @@ configure_file(
- install_dir: get_option('mandir') / 'man8',
- configuration: in_data,
- )
-+
-+install_symlink(
-+ 'ksmbd.addshare',
-+ install_dir: get_option('sbindir'),
-+ pointing_to: '..' / get_option('libexecdir') / 'ksmbd.tools',
-+)
---- a/addshare/share_admin.c
-+++ b/addshare/share_admin.c
-@@ -14,7 +14,7 @@
- #include <fcntl.h>
-
- #include <config_parser.h>
--#include <ksmbdtools.h>
-+#include <tools.h>
-
- #include <management/share.h>
-
---- a/adduser/Makefile.am
-+++ b/adduser/Makefile.am
-@@ -1,12 +1,8 @@
- AM_CFLAGS = -DSYSCONFDIR='"${sysconfdir}"' -DRUNSTATEDIR='"${runstatedir}"' \
- -I$(top_srcdir)/include $(GLIB_CFLAGS) $(LIBNL_CFLAGS) -fno-common
--LIBS = $(GLIB_LIBS)
--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
-+noinst_LIBRARIES = libadduser.a
-+libadduser_a_SOURCES = md4_hash.c user_admin.c adduser.c md4_hash.h user_admin.h
-
- EXTRA_DIST = ksmbd.adduser.8.in
-
-@@ -14,3 +10,11 @@ man_MANS = ksmbd.adduser.8
- $(man_MANS): %: %.in; @$(in_script) $< >$@
-
- CLEANFILES = $(man_MANS)
-+
-+install-exec-hook: uninstall-hook
-+ $(MKDIR_P) $(DESTDIR)$(sbindir)
-+ ( cd $(DESTDIR)$(sbindir) && \
-+ $(LN_S) $(libexecdir)/ksmbd.tools ksmbd.adduser )
-+
-+uninstall-hook:
-+ -rm $(DESTDIR)$(sbindir)/ksmbd.adduser
---- a/adduser/adduser.c
-+++ b/adduser/adduser.c
-@@ -18,7 +18,7 @@
- #include <ctype.h>
-
- #include "config_parser.h"
--#include "ksmbdtools.h"
-+#include "tools.h"
- #include "management/user.h"
- #include "management/share.h"
- #include "user_admin.h"
-@@ -121,7 +121,7 @@ static int sanity_check_user_name_simple
- return 0;
- }
-
--int main(int argc, char *argv[])
-+int adduser_main(int argc, char **argv)
- {
- int ret = -EINVAL;
- char *account = NULL, *password = NULL, *pwddb = NULL, *smbconf = NULL;
---- a/adduser/meson.build
-+++ b/adduser/meson.build
-@@ -1,22 +1,18 @@
--executable(
-- 'ksmbd.adduser',
-+adduser_lib = static_library(
-+ 'adduser',
- 'md4_hash.c',
- 'user_admin.c',
- 'adduser.c',
- 'md4_hash.h',
- 'user_admin.h',
-- dependencies: [
-- glib_dep,
-- libnl_dep,
-- ],
-- include_directories: tools_incdir,
-- link_with: libksmbdtools,
-- install: true,
-- install_dir: get_option('sbindir'),
-+ include_directories: include_dirs,
- c_args: [
- '-DSYSCONFDIR="@0@"'.format(get_option('prefix') / get_option('sysconfdir')),
- '-DRUNSTATEDIR="@0@"'.format(runstatedir),
- ],
-+ dependencies: [
-+ glib_dep,
-+ ],
- )
-
- configure_file(
-@@ -25,3 +21,9 @@ configure_file(
- install_dir: get_option('mandir') / 'man8',
- configuration: in_data,
- )
-+
-+install_symlink(
-+ 'ksmbd.adduser',
-+ install_dir: get_option('sbindir'),
-+ pointing_to: '..' / get_option('libexecdir') / 'ksmbd.tools',
-+)
---- a/adduser/user_admin.c
-+++ b/adduser/user_admin.c
-@@ -15,7 +15,7 @@
- #include <termios.h>
-
- #include <config_parser.h>
--#include <ksmbdtools.h>
-+#include <tools.h>
-
- #include <md4_hash.h>
- #include <user_admin.h>
---- a/configure.ac
-+++ b/configure.ac
-@@ -24,6 +24,8 @@ AC_PROG_CC_STDC
- AM_SILENT_RULES([yes])
- AC_PROG_LIBTOOL
- AC_PROG_SED
-+AC_PROG_MKDIR_P
-+AC_PROG_LN_S
-
- AC_SUBST([in_script], [[\
- '$(SED) -e "s,[@]sbindir[@],$(sbindir),g" \
-@@ -143,11 +145,11 @@ AM_CONDITIONAL(HAVE_LIBKRB5, [test "x$en
-
- AC_CONFIG_FILES([
- Makefile
-- lib/Makefile
-- mountd/Makefile
-- adduser/Makefile
- addshare/Makefile
-+ adduser/Makefile
- control/Makefile
-+ mountd/Makefile
-+ tools/Makefile
- ])
-
- AC_OUTPUT
---- a/control/Makefile.am
-+++ b/control/Makefile.am
-@@ -1,11 +1,8 @@
- AM_CFLAGS = -DSYSCONFDIR='"${sysconfdir}"' -DRUNSTATEDIR='"${runstatedir}"' \
- -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
-+noinst_LIBRARIES = libcontrol.a
-+libcontrol_a_SOURCES = control.c
-
- EXTRA_DIST = ksmbd.control.8.in
-
-@@ -13,3 +10,11 @@ man_MANS = ksmbd.control.8
- $(man_MANS): %: %.in; @$(in_script) $< >$@
-
- CLEANFILES = $(man_MANS)
-+
-+install-exec-hook: uninstall-hook
-+ $(MKDIR_P) $(DESTDIR)$(sbindir)
-+ ( cd $(DESTDIR)$(sbindir) && \
-+ $(LN_S) $(libexecdir)/ksmbd.tools ksmbd.control )
-+
-+uninstall-hook:
-+ -rm $(DESTDIR)$(sbindir)/ksmbd.control
---- a/control/control.c
-+++ b/control/control.c
-@@ -9,7 +9,7 @@
- #include <fcntl.h>
- #include <errno.h>
-
--#include "ksmbdtools.h"
-+#include "tools.h"
- #include "version.h"
-
- static void usage(int status)
-@@ -146,7 +146,7 @@ out:
- return ret;
- }
-
--int main(int argc, char *argv[])
-+int control_main(int argc, char **argv)
- {
- int ret = -EINVAL;
- int c;
---- a/control/meson.build
-+++ b/control/meson.build
-@@ -1,18 +1,14 @@
--executable(
-- 'ksmbd.control',
-+control_lib = static_library(
-+ 'control',
- 'control.c',
-- dependencies: [
-- glib_dep,
-- libnl_dep,
-- ],
-- include_directories: tools_incdir,
-- link_with: libksmbdtools,
-- install: true,
-- install_dir: get_option('sbindir'),
-+ include_directories: include_dirs,
- c_args: [
- '-DSYSCONFDIR="@0@"'.format(get_option('prefix') / get_option('sysconfdir')),
- '-DRUNSTATEDIR="@0@"'.format(runstatedir),
- ],
-+ dependencies: [
-+ glib_dep,
-+ ],
- )
-
- configure_file(
-@@ -21,3 +17,9 @@ configure_file(
- install_dir: get_option('mandir') / 'man8',
- configuration: in_data,
- )
-+
-+install_symlink(
-+ 'ksmbd.control',
-+ install_dir: get_option('sbindir'),
-+ pointing_to: '..' / get_option('libexecdir') / 'ksmbd.tools',
-+)
---- a/include/ksmbdtools.h
-+++ /dev/null
-@@ -1,172 +0,0 @@
--/* SPDX-License-Identifier: GPL-2.0-or-later */
--/*
-- * Copyright (C) 2018 Samsung Electronics Co., Ltd.
-- *
-- * linux-cifsd-devel@lists.sourceforge.net
-- */
--
--#ifndef __KSMBDTOOLS_H__
--#define __KSMBDTOOLS_H__
--
--#ifndef _GNU_SOURCE
--#define _GNU_SOURCE 1
--#endif
--
--#include <errno.h>
--#include <getopt.h>
--#include <glib.h>
--#include <poll.h>
--#include <stdio.h>
--#include <stdlib.h>
--#include <string.h>
--#include <sys/types.h>
--#include <sys/wait.h>
--#include <time.h>
--#include <unistd.h>
--
--#ifdef HAVE_CONFIG_H
--#include <config.h>
--#endif
--
--struct smbconf_global {
-- int flags;
-- int map_to_guest;
-- char *guest_account;
--
-- char *server_string;
-- char *work_group;
-- char *netbios_name;
-- char *server_min_protocol;
-- char *server_max_protocol;
-- char *root_dir;
-- int server_signing;
-- int sessions_cap;
-- int restrict_anon;
-- unsigned short tcp_port;
-- unsigned short ipc_timeout;
-- unsigned int deadtime;
-- int bind_interfaces_only;
-- char **interfaces;
-- unsigned long file_max;
-- unsigned int smb2_max_read;
-- unsigned int smb2_max_write;
-- unsigned int smb2_max_trans;
-- unsigned int smb2_max_credits;
-- unsigned int smbd_max_io_size;
-- unsigned int share_fake_fscaps;
-- unsigned int gen_subauth[3];
-- char *krb5_keytab_file;
-- char *krb5_service_name;
-- char *pwddb;
-- char *smbconf;
--};
--
--#define KSMBD_LOCK_FILE RUNSTATEDIR "/ksmbd.lock"
--
--#define KSMBD_RESTRICT_ANON_TYPE_1 1
--#define KSMBD_RESTRICT_ANON_TYPE_2 2
--
--extern struct smbconf_global global_conf;
--
--#define KSMBD_CONF_MAP_TO_GUEST_NEVER (0)
--#define KSMBD_CONF_MAP_TO_GUEST_BAD_USER (1 << 0)
--#define KSMBD_CONF_MAP_TO_GUEST_BAD_PASSWORD (1 << 1)
--#define KSMBD_CONF_MAP_TO_GUEST_BAD_UID (1 << 2)
--
--#define KSMBD_CONF_DEFAULT_NETBIOS_NAME "KSMBD SERVER"
--#define KSMBD_CONF_DEFAULT_SERVER_STRING "SMB SERVER"
--#define KSMBD_CONF_DEFAULT_WORK_GROUP "WORKGROUP"
--
--#define KSMBD_CONF_DEFAULT_GUEST_ACCOUNT "nobody"
--
--#define KSMBD_CONF_DEFAULT_SESS_CAP 1024
--#define KSMBD_CONF_DEFAULT_TCP_PORT 445
--
--#define KSMBD_CONF_FILE_MAX 10000
--
--#define PATH_PWDDB SYSCONFDIR "/ksmbd/ksmbdpwd.db"
--#define PATH_SMBCONF SYSCONFDIR "/ksmbd/ksmbd.conf"
--#define PATH_SMBCONF_FALLBACK SYSCONFDIR "/ksmbd/smb.conf"
--#define PATH_SUBAUTH SYSCONFDIR "/ksmbd/ksmbd.subauth"
--
--#define KSMBD_HEALTH_START (0)
--#define KSMBD_HEALTH_RUNNING (1 << 0)
--#define KSMBD_SHOULD_RELOAD_CONFIG (1 << 1)
--
--extern int ksmbd_health_status;
--
--#define TRACING_DUMP_NL_MSG 0
--
--#define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0]))
--
--#define STR_HELPER(x) #x
--#define STR(x) STR_HELPER(x)
--
--//---------------------------------------------------------------//
--#define LOGAPP "[%s/%d]:"
--#define PRERR LOGAPP" ERROR: "
--#define PRINF LOGAPP" INFO: "
--#define PRDEBUG LOGAPP" DEBUG: "
--
--#define PR_ERROR 0
--#define PR_INFO 1
--#define PR_DEBUG 2
--
--extern int log_level;
--
--#define PR_LOGGER_STDIO 0
--#define PR_LOGGER_SYSLOG 1
--
--G_GNUC_PRINTF(2, 3)
--extern void __pr_log(int level, const char *fmt, ...);
--extern void set_logger_app_name(const char *an);
--extern const char *get_logger_app_name(void);
--extern void pr_logger_init(int flags);
--extern int set_log_level(int level);
--
--#define pr_log(l, f, ...) \
-- do { \
-- if ((l) <= log_level) \
-- __pr_log((l), (f), get_logger_app_name(), \
-- getpid(), \
-- ##__VA_ARGS__); \
-- } while (0)
--
--#define pr_debug(f, ...) \
-- pr_log(PR_DEBUG, PRDEBUG f, ##__VA_ARGS__)
--#define pr_info(f, ...) \
-- pr_log(PR_INFO, PRINF f, ##__VA_ARGS__)
--#define pr_err(f, ...) \
-- pr_log(PR_ERROR, PRERR f, ##__VA_ARGS__)
--
--//---------------------------------------------------------------//
--
--void pr_hex_dump(const void *mem, size_t sz);
--
--char *base64_encode(unsigned char *src, size_t srclen);
--unsigned char *base64_decode(char const *src, size_t *dstlen);
--
--gchar *ksmbd_gconvert(const gchar *str,
-- gssize str_len,
-- int to_codeset,
-- int from_codeset,
-- gsize *bytes_read,
-- gsize *bytes_written);
--
--enum charset_idx {
-- KSMBD_CHARSET_UTF8 = 0,
-- KSMBD_CHARSET_UTF16LE,
-- KSMBD_CHARSET_UCS2LE,
-- KSMBD_CHARSET_UTF16BE,
-- KSMBD_CHARSET_UCS2BE,
-- KSMBD_CHARSET_MAX = 5,
--};
--
--#define KSMBD_CHARSET_DEFAULT KSMBD_CHARSET_UTF8
--
--extern char *ksmbd_conv_charsets[KSMBD_CHARSET_MAX + 1];
--
--int send_signal_to_ksmbd_mountd(int signo);
--int test_file_access(char *conf);
--
--#endif /* __KSMBDTOOLS_H__ */
---- /dev/null
-+++ b/include/tools.h
-@@ -0,0 +1,177 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later */
-+/*
-+ * Copyright (C) 2018 Samsung Electronics Co., Ltd.
-+ *
-+ * linux-cifsd-devel@lists.sourceforge.net
-+ */
-+
-+#ifndef __TOOLS_H__
-+#define __TOOLS_H__
-+
-+#ifndef _GNU_SOURCE
-+#define _GNU_SOURCE 1
-+#endif
-+
-+#include <errno.h>
-+#include <getopt.h>
-+#include <glib.h>
-+#include <poll.h>
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <string.h>
-+#include <sys/types.h>
-+#include <sys/wait.h>
-+#include <time.h>
-+#include <unistd.h>
-+
-+#ifdef HAVE_CONFIG_H
-+#include <config.h>
-+#endif
-+
-+struct smbconf_global {
-+ int flags;
-+ int map_to_guest;
-+ char *guest_account;
-+
-+ char *server_string;
-+ char *work_group;
-+ char *netbios_name;
-+ char *server_min_protocol;
-+ char *server_max_protocol;
-+ char *root_dir;
-+ int server_signing;
-+ int sessions_cap;
-+ int restrict_anon;
-+ unsigned short tcp_port;
-+ unsigned short ipc_timeout;
-+ unsigned int deadtime;
-+ int bind_interfaces_only;
-+ char **interfaces;
-+ unsigned long file_max;
-+ unsigned int smb2_max_read;
-+ unsigned int smb2_max_write;
-+ unsigned int smb2_max_trans;
-+ unsigned int smb2_max_credits;
-+ unsigned int smbd_max_io_size;
-+ unsigned int share_fake_fscaps;
-+ unsigned int gen_subauth[3];
-+ char *krb5_keytab_file;
-+ char *krb5_service_name;
-+ char *pwddb;
-+ char *smbconf;
-+};
-+
-+#define KSMBD_LOCK_FILE RUNSTATEDIR "/ksmbd.lock"
-+
-+#define KSMBD_RESTRICT_ANON_TYPE_1 1
-+#define KSMBD_RESTRICT_ANON_TYPE_2 2
-+
-+extern struct smbconf_global global_conf;
-+
-+#define KSMBD_CONF_MAP_TO_GUEST_NEVER (0)
-+#define KSMBD_CONF_MAP_TO_GUEST_BAD_USER (1 << 0)
-+#define KSMBD_CONF_MAP_TO_GUEST_BAD_PASSWORD (1 << 1)
-+#define KSMBD_CONF_MAP_TO_GUEST_BAD_UID (1 << 2)
-+
-+#define KSMBD_CONF_DEFAULT_NETBIOS_NAME "KSMBD SERVER"
-+#define KSMBD_CONF_DEFAULT_SERVER_STRING "SMB SERVER"
-+#define KSMBD_CONF_DEFAULT_WORK_GROUP "WORKGROUP"
-+
-+#define KSMBD_CONF_DEFAULT_GUEST_ACCOUNT "nobody"
-+
-+#define KSMBD_CONF_DEFAULT_SESS_CAP 1024
-+#define KSMBD_CONF_DEFAULT_TCP_PORT 445
-+
-+#define KSMBD_CONF_FILE_MAX 10000
-+
-+#define PATH_PWDDB SYSCONFDIR "/ksmbd/ksmbdpwd.db"
-+#define PATH_SMBCONF SYSCONFDIR "/ksmbd/ksmbd.conf"
-+#define PATH_SMBCONF_FALLBACK SYSCONFDIR "/ksmbd/smb.conf"
-+#define PATH_SUBAUTH SYSCONFDIR "/ksmbd/ksmbd.subauth"
-+
-+#define KSMBD_HEALTH_START (0)
-+#define KSMBD_HEALTH_RUNNING (1 << 0)
-+#define KSMBD_SHOULD_RELOAD_CONFIG (1 << 1)
-+
-+extern int ksmbd_health_status;
-+
-+#define TRACING_DUMP_NL_MSG 0
-+
-+#define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0]))
-+
-+#define STR_HELPER(x) #x
-+#define STR(x) STR_HELPER(x)
-+
-+//---------------------------------------------------------------//
-+#define LOGAPP "[%s/%d]:"
-+#define PRERR LOGAPP" ERROR: "
-+#define PRINF LOGAPP" INFO: "
-+#define PRDEBUG LOGAPP" DEBUG: "
-+
-+#define PR_ERROR 0
-+#define PR_INFO 1
-+#define PR_DEBUG 2
-+
-+extern int log_level;
-+
-+#define PR_LOGGER_STDIO 0
-+#define PR_LOGGER_SYSLOG 1
-+
-+G_GNUC_PRINTF(2, 3)
-+extern void __pr_log(int level, const char *fmt, ...);
-+extern void set_logger_app_name(const char *an);
-+extern const char *get_logger_app_name(void);
-+extern void pr_logger_init(int flags);
-+extern int set_log_level(int level);
-+
-+#define pr_log(l, f, ...) \
-+ do { \
-+ if ((l) <= log_level) \
-+ __pr_log((l), (f), get_logger_app_name(), \
-+ getpid(), \
-+ ##__VA_ARGS__); \
-+ } while (0)
-+
-+#define pr_debug(f, ...) \
-+ pr_log(PR_DEBUG, PRDEBUG f, ##__VA_ARGS__)
-+#define pr_info(f, ...) \
-+ pr_log(PR_INFO, PRINF f, ##__VA_ARGS__)
-+#define pr_err(f, ...) \
-+ pr_log(PR_ERROR, PRERR f, ##__VA_ARGS__)
-+
-+//---------------------------------------------------------------//
-+
-+void pr_hex_dump(const void *mem, size_t sz);
-+
-+char *base64_encode(unsigned char *src, size_t srclen);
-+unsigned char *base64_decode(char const *src, size_t *dstlen);
-+
-+gchar *ksmbd_gconvert(const gchar *str,
-+ gssize str_len,
-+ int to_codeset,
-+ int from_codeset,
-+ gsize *bytes_read,
-+ gsize *bytes_written);
-+
-+enum charset_idx {
-+ KSMBD_CHARSET_UTF8 = 0,
-+ KSMBD_CHARSET_UTF16LE,
-+ KSMBD_CHARSET_UCS2LE,
-+ KSMBD_CHARSET_UTF16BE,
-+ KSMBD_CHARSET_UCS2BE,
-+ KSMBD_CHARSET_MAX = 5,
-+};
-+
-+#define KSMBD_CHARSET_DEFAULT KSMBD_CHARSET_UTF8
-+
-+extern char *ksmbd_conv_charsets[KSMBD_CHARSET_MAX + 1];
-+
-+int send_signal_to_ksmbd_mountd(int signo);
-+int test_file_access(char *conf);
-+
-+int addshare_main(int argc, char **argv);
-+int adduser_main(int argc, char **argv);
-+int control_main(int argc, char **argv);
-+int mountd_main(int argc, char **argv);
-+
-+#endif /* __TOOLS_H__ */
---- a/ksmbd-tools.spec
-+++ b/ksmbd-tools.spec
-@@ -16,7 +16,7 @@
- #
-
- Name: ksmbd-tools
--Version: 3.4.6
-+Version: master
- Release: 0
- Summary: ksmbd kernel server userspace utilities
- License: GPL-2.0-or-later
-@@ -53,6 +53,7 @@ make %{?_smp_mflags}
- %{_sbindir}/ksmbd.adduser
- %{_sbindir}/ksmbd.control
- %{_sbindir}/ksmbd.mountd
-+%{_libexecdir}/ksmbd.tools
- %{_mandir}/man8/ksmbd.addshare.8*
- %{_mandir}/man8/ksmbd.adduser.8*
- %{_mandir}/man8/ksmbd.control.8*
---- a/meson.build
-+++ b/meson.build
-@@ -10,10 +10,10 @@ exec awk '/define KSMBD_TOOLS_VERSION /
- check: true,
- ).stdout(),
- default_options: 'c_std=gnu99',
-- meson_version: '>= 0.51.0',
-+ meson_version: '>= 0.61.5',
- )
-
--tools_incdir = include_directories(
-+include_dirs = include_directories(
- '.',
- 'include',
- )
-@@ -151,8 +151,8 @@ configure_file(
- configuration: in_data,
- )
-
--subdir('lib')
- subdir('addshare')
- subdir('adduser')
- subdir('control')
- subdir('mountd')
-+subdir('tools')
---- a/mountd/Makefile.am
-+++ b/mountd/Makefile.am
-@@ -1,12 +1,9 @@
- AM_CFLAGS = -DSYSCONFDIR='"${sysconfdir}"' -DRUNSTATEDIR='"${runstatedir}"' \
- -I$(top_srcdir)/include $(GLIB_CFLAGS) $(LIBNL_CFLAGS) -fno-common
--LIBS = $(GLIB_LIBS) $(LIBNL_LIBS) $(LIBKRB5_LIBS)
--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 smbacl.c rpc_samr.c rpc_lsarpc.c
-+noinst_LIBRARIES = libmountd.a
-+libmountd_a_SOURCES = worker.c ipc.c rpc.c rpc_srvsvc.c rpc_wkssvc.c mountd.c \
-+ smbacl.c rpc_samr.c rpc_lsarpc.c
-
- EXTRA_DIST = ksmbd.mountd.8.in
-
-@@ -14,3 +11,11 @@ man_MANS = ksmbd.mountd.8
- $(man_MANS): %: %.in; @$(in_script) $< >$@
-
- CLEANFILES = $(man_MANS)
-+
-+install-exec-hook: uninstall-hook
-+ $(MKDIR_P) $(DESTDIR)$(sbindir)
-+ ( cd $(DESTDIR)$(sbindir) && \
-+ $(LN_S) $(libexecdir)/ksmbd.tools ksmbd.mountd )
-+
-+uninstall-hook:
-+ -rm $(DESTDIR)$(sbindir)/ksmbd.mountd
---- a/mountd/ipc.c
-+++ b/mountd/ipc.c
-@@ -17,7 +17,7 @@
-
- #include <linux/ksmbd_server.h>
-
--#include <ksmbdtools.h>
-+#include <tools.h>
- #include <ipc.h>
- #include <worker.h>
- #include <config_parser.h>
---- a/mountd/meson.build
-+++ b/mountd/meson.build
-@@ -1,5 +1,5 @@
--executable(
-- 'ksmbd.mountd',
-+mountd_lib = static_library(
-+ 'mountd',
- 'worker.c',
- 'ipc.c',
- 'rpc.c',
-@@ -9,18 +9,15 @@ executable(
- 'smbacl.c',
- 'rpc_samr.c',
- 'rpc_lsarpc.c',
-- dependencies: [
-- glib_dep,
-- libnl_dep,
-- ],
-- include_directories: tools_incdir,
-- link_with: libksmbdtools,
-- install: true,
-- install_dir: get_option('sbindir'),
-+ include_directories: include_dirs,
- c_args: [
- '-DSYSCONFDIR="@0@"'.format(get_option('prefix') / get_option('sysconfdir')),
- '-DRUNSTATEDIR="@0@"'.format(runstatedir),
- ],
-+ dependencies: [
-+ glib_dep,
-+ libnl_dep,
-+ ],
- )
-
- configure_file(
-@@ -29,3 +26,9 @@ configure_file(
- install_dir: get_option('mandir') / 'man8',
- configuration: in_data,
- )
-+
-+install_symlink(
-+ 'ksmbd.mountd',
-+ install_dir: get_option('sbindir'),
-+ pointing_to: '..' / get_option('libexecdir') / 'ksmbd.tools',
-+)
---- a/mountd/mountd.c
-+++ b/mountd/mountd.c
-@@ -5,7 +5,7 @@
- * linux-cifsd-devel@lists.sourceforge.net
- */
-
--#include <ksmbdtools.h>
-+#include <tools.h>
-
- #ifndef _GNU_SOURCE
- #define _GNU_SOURCE
-@@ -509,7 +509,7 @@ out:
- return 0;
- }
-
--int main(int argc, char *argv[])
-+int mountd_main(int argc, char **argv)
- {
- int ret = -EINVAL;
- int c;
---- a/mountd/rpc.c
-+++ b/mountd/rpc.c
-@@ -16,7 +16,7 @@
- #include <rpc_wkssvc.h>
- #include <rpc_samr.h>
- #include <rpc_lsarpc.h>
--#include <ksmbdtools.h>
-+#include <tools.h>
-
- static GHashTable *pipes_table;
- static GRWLock pipes_table_lock;
---- a/mountd/rpc_lsarpc.c
-+++ b/mountd/rpc_lsarpc.c
-@@ -16,7 +16,7 @@
- #include <rpc.h>
- #include <rpc_lsarpc.h>
- #include <smbacl.h>
--#include <ksmbdtools.h>
-+#include <tools.h>
-
- #define LSARPC_OPNUM_DS_ROLE_GET_PRIMARY_DOMAIN_INFO 0
- #define LSARPC_OPNUM_OPEN_POLICY2 44
---- a/mountd/rpc_samr.c
-+++ b/mountd/rpc_samr.c
-@@ -15,7 +15,7 @@
- #include <rpc.h>
- #include <rpc_samr.h>
- #include <smbacl.h>
--#include <ksmbdtools.h>
-+#include <tools.h>
-
- #define SAMR_OPNUM_CONNECT5 64
- #define SAMR_OPNUM_ENUM_DOMAIN 6
---- a/mountd/rpc_srvsvc.c
-+++ b/mountd/rpc_srvsvc.c
-@@ -15,7 +15,7 @@
-
- #include <rpc.h>
- #include <rpc_srvsvc.h>
--#include <ksmbdtools.h>
-+#include <tools.h>
-
- #define SHARE_TYPE_TEMP 0x40000000
- #define SHARE_TYPE_HIDDEN 0x80000000
---- a/mountd/rpc_wkssvc.c
-+++ b/mountd/rpc_wkssvc.c
-@@ -15,7 +15,7 @@
-
- #include <rpc.h>
- #include <rpc_wkssvc.h>
--#include <ksmbdtools.h>
-+#include <tools.h>
-
- #define WKSSVC_NETWKSTA_GET_INFO (0)
-
---- a/mountd/smbacl.c
-+++ b/mountd/smbacl.c
-@@ -7,7 +7,7 @@
- */
-
- #include <smbacl.h>
--#include <ksmbdtools.h>
-+#include <tools.h>
- #include <glib.h>
-
- static const struct smb_sid sid_domain = {1, 1, {0, 0, 0, 0, 0, 5},
---- a/mountd/worker.c
-+++ b/mountd/worker.c
-@@ -9,7 +9,7 @@
- #include <errno.h>
- #include <linux/ksmbd_server.h>
-
--#include <ksmbdtools.h>
-+#include <tools.h>
- #include <worker.h>
- #include <ipc.h>
- #include <rpc.h>
---- a/lib/Makefile.am
-+++ /dev/null
-@@ -1,18 +0,0 @@
--AM_CFLAGS = -DSYSCONFDIR='"${sysconfdir}"' -DRUNSTATEDIR='"${runstatedir}"' \
-- -I$(top_srcdir)/include $(GLIB_CFLAGS) $(LIBKRB5_CFLAGS) -fno-common
--LIBS = $(GLIB_LIBS)
--
--noinst_LIBRARIES = libksmbdtools.a
--libksmbdtools_a_SOURCES = management/tree_conn.c \
-- management/user.c \
-- management/share.c \
-- management/session.c \
-- config_parser.c \
-- ksmbdtools.c
--
--if HAVE_LIBKRB5
--libksmbdtools_a_SOURCES += management/spnego.c \
-- asn1.c \
-- management/spnego_krb5.c \
-- management/spnego_mech.h
--endif
---- /dev/null
-+++ b/tools/Makefile.am
-@@ -0,0 +1,21 @@
-+AM_CFLAGS = -DSYSCONFDIR='"${sysconfdir}"' -DRUNSTATEDIR='"${runstatedir}"' \
-+ -I$(top_srcdir)/include $(GLIB_CFLAGS) $(LIBKRB5_CFLAGS) -fno-common
-+LIBS = $(GLIB_LIBS) $(LIBNL_LIBS) $(LIBKRB5_LIBS)
-+
-+libexec_PROGRAMS = ksmbd.tools
-+ksmbd_tools_SOURCES = management/tree_conn.c \
-+ management/user.c \
-+ management/share.c \
-+ management/session.c \
-+ config_parser.c \
-+ tools.c
-+if HAVE_LIBKRB5
-+ksmbd_tools_SOURCES += management/spnego.c \
-+ asn1.c \
-+ management/spnego_krb5.c \
-+ management/spnego_mech.h
-+endif
-+ksmbd_tools_LDADD = $(top_builddir)/addshare/libaddshare.a \
-+ $(top_builddir)/adduser/libadduser.a \
-+ $(top_builddir)/control/libcontrol.a \
-+ $(top_builddir)/mountd/libmountd.a
---- a/lib/config_parser.c
-+++ /dev/null
-@@ -1,770 +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 <string.h>
--#include <glib/gstdio.h>
--#include <sys/stat.h>
--#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>
--
--struct smbconf_global global_conf;
--struct smbconf_parser parser;
--struct smbconf_group *global_group, *ipc_group;
--
--unsigned long long memparse(const char *v)
--{
-- char *eptr;
--
-- unsigned long long ret = strtoull(v, &eptr, 0);
--
-- switch (*eptr) {
-- case 'E':
-- case 'e':
-- ret <<= 10;
-- case 'P':
-- case 'p':
-- ret <<= 10;
-- case 'T':
-- case 't':
-- ret <<= 10;
-- case 'G':
-- case 'g':
-- ret <<= 10;
-- case 'M':
-- case 'm':
-- ret <<= 10;
-- case 'K':
-- case 'k':
-- ret <<= 10;
-- }
--
-- return ret;
--}
--
--static void kv_release_cb(gpointer p)
--{
-- g_free(p);
--}
--
--static int is_ascii_space_tab(char c)
--{
-- return c == ' ' || c == '\t';
--}
--
--static int is_a_comment(char *line)
--{
-- return (*line == 0x00 || *line == ';' || *line == '\n' || *line == '#');
--}
--
--static int is_a_group(char *line)
--{
-- char *p = line;
--
-- if (*p != '[')
-- return 0;
-- p++;
-- while (*p && *p != ']')
-- p = g_utf8_find_next_char(p, NULL);
-- if (*p != ']')
-- return 0;
-- return 1;
--}
--
--static int add_new_group(char *line)
--{
-- char *begin = line;
-- char *end = line;
-- char *name = NULL;
-- struct smbconf_group *group = NULL;
-- struct smbconf_group *lookup;
--
-- while (*end && *end != ']')
-- end = g_utf8_find_next_char(end, NULL);
--
-- name = g_strndup(begin + 1, end - begin - 1);
-- if (!name)
-- goto out_free;
--
-- lookup = g_hash_table_lookup(parser.groups, name);
-- if (lookup) {
-- parser.current = lookup;
-- pr_info("Multiple definitions for group `%s'\n", name);
-- g_free(name);
-- return 0;
-- }
--
-- group = g_malloc(sizeof(struct smbconf_group));
-- group->cb_mode = GROUPS_CALLBACK_NONE;
-- group->name = name;
-- group->kv = g_hash_table_new_full(g_str_hash,
-- g_str_equal,
-- kv_release_cb,
-- kv_release_cb);
-- if (!group->kv)
-- goto out_free;
--
-- parser.current = group;
-- g_hash_table_insert(parser.groups, group->name, group);
-- return 0;
--
--out_free:
-- g_free(name);
-- if (group && group->kv)
-- g_hash_table_destroy(group->kv);
-- g_free(group);
-- return -ENOMEM;
--}
--
--static int add_group_key_value(char *line)
--{
-- char *key, *value;
--
-- key = strchr(line, '=');
-- if (!key)
-- return -EINVAL;
--
-- value = key;
-- *key = 0x00;
-- key--;
-- value++;
--
-- while (is_ascii_space_tab(*key))
-- key--;
-- while (is_ascii_space_tab(*value))
-- value++;
--
-- if (is_a_comment(value))
-- return 0;
--
-- if (g_hash_table_lookup(parser.current->kv, key)) {
-- pr_info("Multiple key-value definitions [%s] %s\n",
-- parser.current->name, key);
-- return 0;
-- }
--
-- key = g_strndup(line, key - line + 1);
-- value = g_strdup(value);
--
-- if (!key || !value) {
-- g_free(key);
-- g_free(value);
-- return -ENOMEM;
-- }
--
-- g_hash_table_insert(parser.current->kv, key, value);
-- return 0;
--}
--
--static int process_smbconf_entry(char *data)
--{
-- while (is_ascii_space_tab(*data))
-- data++;
--
-- if (is_a_comment(data))
-- return 0;
--
-- if (is_a_group(data))
-- return add_new_group(data);
--
-- return add_group_key_value(data);
--}
--
--static int __mmap_parse_file(const char *fname, int (*callback)(char *data))
--{
-- GMappedFile *file;
-- GError *err = NULL;
-- gchar *contents;
-- int len;
-- char *delim;
-- int fd, ret = 0;
--
-- fd = g_open(fname, O_RDONLY, 0);
-- if (fd == -1) {
-- ret = -errno;
-- pr_debug("Can't open `%s': %m\n", fname);
-- return ret;
-- }
--
-- file = g_mapped_file_new_from_fd(fd, FALSE, &err);
-- if (err) {
-- pr_err("Can't map `%s' to memory: %s\n", fname, err->message);
-- g_error_free(err);
-- ret = -EINVAL;
-- goto out;
-- }
--
-- contents = g_mapped_file_get_contents(file);
-- if (!contents)
-- goto out;
--
-- len = g_mapped_file_get_length(file);
-- while (len > 0) {
-- delim = strchr(contents, '\n');
-- if (!delim)
-- delim = contents + len - 1;
--
-- if (delim) {
-- size_t sz = delim - contents;
-- char *data;
--
-- if (delim == contents) {
-- contents = delim + 1;
-- len--;
-- continue;
-- }
--
-- if (!sz)
-- break;
--
-- data = g_strndup(contents, sz);
-- ret = callback(data);
-- if (ret) {
-- g_free(data);
-- goto out;
-- }
--
-- g_free(data);
-- contents = delim + 1;
-- len -= (sz + 1);
-- }
-- }
--
-- ret = 0;
--out:
-- if (file)
-- g_mapped_file_unref(file);
--
-- if (fd) {
-- g_close(fd, &err);
-- if (err) {
-- pr_err("Can't close `%s': %s\n", fname, err->message);
-- g_error_free(err);
-- }
-- }
-- return ret;
--}
--
--static int init_smbconf_parser(void)
--{
-- if (parser.groups)
-- return 0;
--
-- parser.groups = g_hash_table_new(shm_share_name_hash,
-- shm_share_name_equal);
-- if (!parser.groups)
-- return -ENOMEM;
-- return 0;
--}
--
--static void release_smbconf_group(gpointer k, gpointer v, gpointer user_data)
--{
-- struct smbconf_group *g = v;
--
-- g_hash_table_destroy(g->kv);
-- g_free(g->name);
-- g_free(g);
--}
--
--static void release_smbconf_parser(void)
--{
-- if (!parser.groups)
-- return;
--
-- g_hash_table_foreach(parser.groups, release_smbconf_group, NULL);
-- g_hash_table_destroy(parser.groups);
-- parser.groups = NULL;
--}
--
--char *cp_ltrim(char *v)
--{
-- if (!v)
-- return NULL;
--
-- while (*v && *v == ' ')
-- v++;
-- if (*v == 0x00)
-- return NULL;
-- return v;
--}
--
--int cp_key_cmp(char *k, char *v)
--{
-- if (!k || !v)
-- return -1;
-- return g_ascii_strncasecmp(k, v, strlen(v));
--}
--
--char *cp_get_group_kv_string(char *v)
--{
-- return g_strdup(v);
--}
--
--int cp_get_group_kv_bool(char *v)
--{
-- if (!g_ascii_strncasecmp(v, "yes", 3) ||
-- !g_ascii_strncasecmp(v, "1", 1) ||
-- !g_ascii_strncasecmp(v, "true", 4) ||
-- !g_ascii_strncasecmp(v, "enable", 6))
-- return 1;
-- return 0;
--}
--
--int cp_get_group_kv_config_opt(char *v)
--{
-- if (!g_ascii_strncasecmp(v, "disabled", 8))
-- return KSMBD_CONFIG_OPT_DISABLED;
-- if (!g_ascii_strncasecmp(v, "enabled", 7))
-- return KSMBD_CONFIG_OPT_ENABLED;
-- if (!g_ascii_strncasecmp(v, "auto", 4))
-- return KSMBD_CONFIG_OPT_AUTO;
-- if (!g_ascii_strncasecmp(v, "mandatory", 9))
-- return KSMBD_CONFIG_OPT_MANDATORY;
-- return KSMBD_CONFIG_OPT_DISABLED;
--}
--
--unsigned long cp_get_group_kv_long_base(char *v, int base)
--{
-- return strtoul(v, NULL, base);
--}
--
--unsigned long cp_get_group_kv_long(char *v)
--{
-- return cp_get_group_kv_long_base(v, 10);
--}
--
--char **cp_get_group_kv_list(char *v)
--{
-- /*
-- * SMB conf lists are "tabs, spaces, commas" separated.
-- */
-- return g_strsplit_set(v, "\t ,", -1);
--}
--
--void cp_group_kv_list_free(char **list)
--{
-- g_strfreev(list);
--}
--
--static int cp_add_global_guest_account(gpointer _v)
--{
-- struct ksmbd_user *user;
--
-- if (usm_add_new_user(cp_get_group_kv_string(_v),
-- g_strdup("NULL"))) {
-- pr_err("Unable to add guest account\n");
-- return -ENOMEM;
-- }
--
-- user = usm_lookup_user(_v);
-- if (!user) {
-- pr_err("Unable to find user `%s'\n", (char *) _v);
-- return -EINVAL;
-- }
--
-- set_user_flag(user, KSMBD_USER_FLAG_GUEST_ACCOUNT);
-- put_ksmbd_user(user);
-- global_conf.guest_account = cp_get_group_kv_string(_v);
-- return 0;
--}
--
--static gboolean global_group_kv(gpointer _k, gpointer _v, gpointer user_data)
--{
-- if (!cp_key_cmp(_k, "server string")) {
-- global_conf.server_string = cp_get_group_kv_string(_v);
-- return TRUE;
-- }
--
-- if (!cp_key_cmp(_k, "workgroup")) {
-- global_conf.work_group = cp_get_group_kv_string(_v);
-- return TRUE;
-- }
--
-- if (!cp_key_cmp(_k, "netbios name")) {
-- global_conf.netbios_name = cp_get_group_kv_string(_v);
-- return TRUE;
-- }
--
-- if (!cp_key_cmp(_k, "server min protocol")) {
-- global_conf.server_min_protocol = cp_get_group_kv_string(_v);
-- return TRUE;
-- }
--
-- if (!cp_key_cmp(_k, "server signing")) {
-- global_conf.server_signing = cp_get_group_kv_config_opt(_v);
-- return TRUE;
-- }
--
-- if (!cp_key_cmp(_k, "server max protocol")) {
-- global_conf.server_max_protocol = cp_get_group_kv_string(_v);
-- return TRUE;
-- }
--
-- if (!cp_key_cmp(_k, "guest account")) {
-- cp_add_global_guest_account(_v);
-- return TRUE;
-- }
--
-- if (!cp_key_cmp(_k, "max active sessions")) {
-- global_conf.sessions_cap = cp_get_group_kv_long(_v);
-- return TRUE;
-- }
--
-- if (!cp_key_cmp(_k, "tcp port")) {
-- if (!global_conf.tcp_port)
-- global_conf.tcp_port = cp_get_group_kv_long(_v);
-- return TRUE;
-- }
--
-- if (!cp_key_cmp(_k, "ipc timeout")) {
-- global_conf.ipc_timeout = cp_get_group_kv_long(_v);
-- return TRUE;
-- }
--
-- if (!cp_key_cmp(_k, "max open files")) {
-- global_conf.file_max = cp_get_group_kv_long(_v);
-- return TRUE;
-- }
--
-- if (!cp_key_cmp(_k, "restrict anonymous")) {
-- global_conf.restrict_anon = cp_get_group_kv_long(_v);
-- if (global_conf.restrict_anon > KSMBD_RESTRICT_ANON_TYPE_2 ||
-- global_conf.restrict_anon < 0) {
-- global_conf.restrict_anon = 0;
-- pr_err("Invalid restrict anonymous value\n");
-- }
--
-- return TRUE;
-- }
--
-- if (!cp_key_cmp(_k, "map to guest")) {
-- global_conf.map_to_guest = KSMBD_CONF_MAP_TO_GUEST_NEVER;
-- if (!cp_key_cmp(_v, "bad user"))
-- global_conf.map_to_guest =
-- KSMBD_CONF_MAP_TO_GUEST_BAD_USER;
-- if (!cp_key_cmp(_v, "bad password"))
-- global_conf.map_to_guest =
-- KSMBD_CONF_MAP_TO_GUEST_BAD_PASSWORD;
-- if (!cp_key_cmp(_v, "bad uid"))
-- global_conf.map_to_guest =
-- KSMBD_CONF_MAP_TO_GUEST_BAD_UID;
-- return TRUE;
-- }
--
-- if (!cp_key_cmp(_k, "bind interfaces only")) {
-- global_conf.bind_interfaces_only = cp_get_group_kv_bool(_v);
-- return TRUE;
-- }
--
-- if (!cp_key_cmp(_k, "interfaces")) {
-- global_conf.interfaces = cp_get_group_kv_list(_v);
-- return TRUE;
-- }
--
-- if (!cp_key_cmp(_k, "deadtime")) {
-- global_conf.deadtime = cp_get_group_kv_long(_v);
-- return TRUE;
-- }
--
-- if (!cp_key_cmp(_k, "smb2 leases")) {
-- if (cp_get_group_kv_bool(_v))
-- global_conf.flags |= KSMBD_GLOBAL_FLAG_SMB2_LEASES;
-- else
-- global_conf.flags &= ~KSMBD_GLOBAL_FLAG_SMB2_LEASES;
--
-- return TRUE;
-- }
--
-- if (!cp_key_cmp(_k, "root directory")) {
-- global_conf.root_dir = cp_get_group_kv_string(_v);
-- return TRUE;
-- }
--
-- if (!cp_key_cmp(_k, "smb2 max read")) {
-- global_conf.smb2_max_read = memparse(_v);
-- return TRUE;
-- }
--
-- if (!cp_key_cmp(_k, "smb2 max write")) {
-- global_conf.smb2_max_write = memparse(_v);
-- return TRUE;
-- }
--
-- if (!cp_key_cmp(_k, "smb2 max trans")) {
-- global_conf.smb2_max_trans = memparse(_v);
-- return TRUE;
-- }
--
-- if (!cp_key_cmp(_k, "smb3 encryption")) {
-- if (cp_get_group_kv_bool(_v))
-- global_conf.flags |= KSMBD_GLOBAL_FLAG_SMB3_ENCRYPTION;
-- else
-- global_conf.flags &= ~KSMBD_GLOBAL_FLAG_SMB3_ENCRYPTION;
--
-- return TRUE;
-- }
--
-- if (!cp_key_cmp(_k, "share:fake_fscaps")) {
-- global_conf.share_fake_fscaps = cp_get_group_kv_long(_v);
-- return TRUE;
-- }
--
-- if (!cp_key_cmp(_k, "kerberos service name")) {
-- global_conf.krb5_service_name = cp_get_group_kv_string(_v);
-- return TRUE;
-- }
--
-- if (!cp_key_cmp(_k, "kerberos keytab file")) {
-- global_conf.krb5_keytab_file = cp_get_group_kv_string(_v);
-- return TRUE;
-- }
--
-- if (!cp_key_cmp(_k, "server multi channel support")) {
-- if (cp_get_group_kv_bool(_v))
-- global_conf.flags |= KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL;
-- else
-- global_conf.flags &= ~KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL;
--
-- return TRUE;
-- }
--
-- if (!cp_key_cmp(_k, "smb2 max credits")) {
-- global_conf.smb2_max_credits = memparse(_v);
-- return TRUE;
-- }
--
-- if (!cp_key_cmp(_k, "smbd max io size")) {
-- global_conf.smbd_max_io_size = memparse(_v);
-- return TRUE;
-- }
--
-- /* At this point, this is an option that must be applied to all shares */
-- return FALSE;
--}
--
--static void global_conf_default(void)
--{
-- /* The SPARSE_FILES file system capability flag is set by default */
-- global_conf.share_fake_fscaps = 64;
--}
--
--static void global_conf_create(void)
--{
-- if (!global_group || global_group->cb_mode != GROUPS_CALLBACK_INIT)
-- return;
--
-- /*
-- * This will transfer server options to global_conf, and leave behind
-- * in the global parser group, the options that must be applied to every
-- * share
-- */
-- g_hash_table_foreach_remove(global_group->kv, global_group_kv, NULL);
--}
--
--static void append_key_value(gpointer _k, gpointer _v, gpointer user_data)
--{
-- GHashTable *receiver = (GHashTable *)user_data;
--
-- /* Don't override local share options */
-- if (!g_hash_table_lookup(receiver, _k))
-- g_hash_table_insert(receiver, g_strdup(_k), g_strdup(_v));
--}
--
--static void global_conf_update(struct smbconf_group *group)
--{
-- if (!global_group)
-- return;
--
-- g_hash_table_foreach(global_group->kv, append_key_value, group->kv);
--}
--
--static void global_conf_fixup_missing(void)
--{
-- /*
-- * Set default global parameters which were not specified
-- * in smb.conf
-- */
-- if (!global_conf.file_max)
-- global_conf.file_max = KSMBD_CONF_FILE_MAX;
-- if (!global_conf.server_string)
-- global_conf.server_string =
-- cp_get_group_kv_string(
-- KSMBD_CONF_DEFAULT_SERVER_STRING);
-- if (!global_conf.netbios_name)
-- global_conf.netbios_name =
-- cp_get_group_kv_string(KSMBD_CONF_DEFAULT_NETBIOS_NAME);
-- if (!global_conf.work_group)
-- global_conf.work_group =
-- cp_get_group_kv_string(KSMBD_CONF_DEFAULT_WORK_GROUP);
-- if (!global_conf.tcp_port)
-- global_conf.tcp_port = KSMBD_CONF_DEFAULT_TCP_PORT;
--
-- if (global_conf.sessions_cap <= 0)
-- global_conf.sessions_cap = KSMBD_CONF_DEFAULT_SESS_CAP;
--
-- if (!global_conf.guest_account &&
-- cp_add_global_guest_account(KSMBD_CONF_DEFAULT_GUEST_ACCOUNT))
-- pr_err("Unable to add guest account\n");
--}
--
--static void groups_callback(gpointer _k, gpointer _v, gpointer user_data)
--{
-- struct smbconf_group *group = (struct smbconf_group *)_v;
-- unsigned short cb_mode = *(unsigned short *)user_data;
--
-- if (group == global_group)
-- return;
--
-- group->cb_mode = cb_mode;
--
-- if (group != ipc_group)
-- global_conf_update(group);
--
-- shm_add_new_share(group);
--}
--
--static int cp_add_ipc_group(void)
--{
-- char *comment = NULL, *guest = NULL;
-- int ret = 0;
--
-- if (ipc_group)
-- return ret;
--
-- comment = g_strdup("comment = IPC share");
-- guest = g_strdup("guest ok = yes");
-- ret = add_new_group("[IPC$]");
-- ret |= add_group_key_value(comment);
-- ret |= add_group_key_value(guest);
-- if (ret) {
-- pr_err("Unable to add IPC$ share\n");
-- ret = -EINVAL;
-- goto out;
-- }
--
-- ipc_group = g_hash_table_lookup(parser.groups, "ipc$");
--out:
-- g_free(comment);
-- g_free(guest);
-- return ret;
--}
--
--static int __cp_parse_smbconfig(const char *smbconf, GHFunc cb,
-- unsigned short cb_mode)
--{
-- int ret;
--
-- global_conf_default();
--
-- ret = cp_smbconfig_hash_create(smbconf);
-- if (ret)
-- return ret;
--
-- ret = cp_add_ipc_group();
-- if (ret)
-- goto out;
--
-- global_group = g_hash_table_lookup(parser.groups, "global");
-- if (global_group)
-- global_group->cb_mode = cb_mode;
--
-- global_conf_create();
-- g_hash_table_foreach(parser.groups, groups_callback, &cb_mode);
-- global_conf_fixup_missing();
--out:
-- cp_smbconfig_destroy();
-- return ret;
--}
--
--int cp_parse_reload_smbconf(const char *smbconf)
--{
-- return __cp_parse_smbconfig(smbconf, groups_callback,
-- GROUPS_CALLBACK_REINIT);
--}
--
--int cp_parse_smbconf(const char *smbconf)
--{
-- return __cp_parse_smbconfig(smbconf, groups_callback,
-- GROUPS_CALLBACK_INIT);
--}
--
--int cp_parse_pwddb(const char *pwddb)
--{
-- return __mmap_parse_file(pwddb, usm_add_update_user_from_pwdentry);
--}
--
--int cp_smbconfig_hash_create(const char *smbconf)
--{
-- int ret = init_smbconf_parser();
--
-- if (ret)
-- return ret;
-- return __mmap_parse_file(smbconf, process_smbconf_entry);
--}
--
--int cp_parse_subauth(void)
--{
-- return __mmap_parse_file(PATH_SUBAUTH, usm_add_subauth_global_conf);
--}
--
--void cp_smbconfig_destroy(void)
--{
-- release_smbconf_parser();
--}
--
--int cp_parse_external_smbconf_group(char *name, char *opts)
--{
-- char *pos;
-- int i, len;
--
-- if (init_smbconf_parser())
-- return -EINVAL;
--
-- if (!opts || !name)
-- return -EINVAL;
--
-- len = strlen(opts);
-- /* fake smb.conf input */
-- for (i = 0; i < KSMBD_SHARE_CONF_MAX; i++) {
-- pos = strstr(opts, KSMBD_SHARE_CONF[i]);
-- if (!pos)
-- continue;
-- if (pos != opts)
-- *(pos - 1) = '\n';
-- }
--
-- if (add_new_group(name))
-- goto error;
--
-- /* split input and feed to normal process_smbconf_entry() */
-- while (len) {
-- char *delim = strchr(opts, '\n');
--
-- if (delim) {
-- *delim = 0x00;
-- len -= delim - opts;
-- } else {
-- len = 0;
-- }
--
-- process_smbconf_entry(opts);
-- if (delim)
-- opts = delim + 1;
-- }
-- return 0;
--
--error:
-- cp_smbconfig_destroy();
-- return -EINVAL;
--}
---- /dev/null
-+++ b/tools/config_parser.c
-@@ -0,0 +1,770 @@
-+// 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 <string.h>
-+#include <glib/gstdio.h>
-+#include <sys/stat.h>
-+#include <sys/types.h>
-+#include <unistd.h>
-+#include <fcntl.h>
-+#include <linux/ksmbd_server.h>
-+
-+#include <config_parser.h>
-+#include <tools.h>
-+#include <management/user.h>
-+#include <management/share.h>
-+
-+struct smbconf_global global_conf;
-+struct smbconf_parser parser;
-+struct smbconf_group *global_group, *ipc_group;
-+
-+unsigned long long memparse(const char *v)
-+{
-+ char *eptr;
-+
-+ unsigned long long ret = strtoull(v, &eptr, 0);
-+
-+ switch (*eptr) {
-+ case 'E':
-+ case 'e':
-+ ret <<= 10;
-+ case 'P':
-+ case 'p':
-+ ret <<= 10;
-+ case 'T':
-+ case 't':
-+ ret <<= 10;
-+ case 'G':
-+ case 'g':
-+ ret <<= 10;
-+ case 'M':
-+ case 'm':
-+ ret <<= 10;
-+ case 'K':
-+ case 'k':
-+ ret <<= 10;
-+ }
-+
-+ return ret;
-+}
-+
-+static void kv_release_cb(gpointer p)
-+{
-+ g_free(p);
-+}
-+
-+static int is_ascii_space_tab(char c)
-+{
-+ return c == ' ' || c == '\t';
-+}
-+
-+static int is_a_comment(char *line)
-+{
-+ return (*line == 0x00 || *line == ';' || *line == '\n' || *line == '#');
-+}
-+
-+static int is_a_group(char *line)
-+{
-+ char *p = line;
-+
-+ if (*p != '[')
-+ return 0;
-+ p++;
-+ while (*p && *p != ']')
-+ p = g_utf8_find_next_char(p, NULL);
-+ if (*p != ']')
-+ return 0;
-+ return 1;
-+}
-+
-+static int add_new_group(char *line)
-+{
-+ char *begin = line;
-+ char *end = line;
-+ char *name = NULL;
-+ struct smbconf_group *group = NULL;
-+ struct smbconf_group *lookup;
-+
-+ while (*end && *end != ']')
-+ end = g_utf8_find_next_char(end, NULL);
-+
-+ name = g_strndup(begin + 1, end - begin - 1);
-+ if (!name)
-+ goto out_free;
-+
-+ lookup = g_hash_table_lookup(parser.groups, name);
-+ if (lookup) {
-+ parser.current = lookup;
-+ pr_info("Multiple definitions for group `%s'\n", name);
-+ g_free(name);
-+ return 0;
-+ }
-+
-+ group = g_malloc(sizeof(struct smbconf_group));
-+ group->cb_mode = GROUPS_CALLBACK_NONE;
-+ group->name = name;
-+ group->kv = g_hash_table_new_full(g_str_hash,
-+ g_str_equal,
-+ kv_release_cb,
-+ kv_release_cb);
-+ if (!group->kv)
-+ goto out_free;
-+
-+ parser.current = group;
-+ g_hash_table_insert(parser.groups, group->name, group);
-+ return 0;
-+
-+out_free:
-+ g_free(name);
-+ if (group && group->kv)
-+ g_hash_table_destroy(group->kv);
-+ g_free(group);
-+ return -ENOMEM;
-+}
-+
-+static int add_group_key_value(char *line)
-+{
-+ char *key, *value;
-+
-+ key = strchr(line, '=');
-+ if (!key)
-+ return -EINVAL;
-+
-+ value = key;
-+ *key = 0x00;
-+ key--;
-+ value++;
-+
-+ while (is_ascii_space_tab(*key))
-+ key--;
-+ while (is_ascii_space_tab(*value))
-+ value++;
-+
-+ if (is_a_comment(value))
-+ return 0;
-+
-+ if (g_hash_table_lookup(parser.current->kv, key)) {
-+ pr_info("Multiple key-value definitions [%s] %s\n",
-+ parser.current->name, key);
-+ return 0;
-+ }
-+
-+ key = g_strndup(line, key - line + 1);
-+ value = g_strdup(value);
-+
-+ if (!key || !value) {
-+ g_free(key);
-+ g_free(value);
-+ return -ENOMEM;
-+ }
-+
-+ g_hash_table_insert(parser.current->kv, key, value);
-+ return 0;
-+}
-+
-+static int process_smbconf_entry(char *data)
-+{
-+ while (is_ascii_space_tab(*data))
-+ data++;
-+
-+ if (is_a_comment(data))
-+ return 0;
-+
-+ if (is_a_group(data))
-+ return add_new_group(data);
-+
-+ return add_group_key_value(data);
-+}
-+
-+static int __mmap_parse_file(const char *fname, int (*callback)(char *data))
-+{
-+ GMappedFile *file;
-+ GError *err = NULL;
-+ gchar *contents;
-+ int len;
-+ char *delim;
-+ int fd, ret = 0;
-+
-+ fd = g_open(fname, O_RDONLY, 0);
-+ if (fd == -1) {
-+ ret = -errno;
-+ pr_debug("Can't open `%s': %m\n", fname);
-+ return ret;
-+ }
-+
-+ file = g_mapped_file_new_from_fd(fd, FALSE, &err);
-+ if (err) {
-+ pr_err("Can't map `%s' to memory: %s\n", fname, err->message);
-+ g_error_free(err);
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ contents = g_mapped_file_get_contents(file);
-+ if (!contents)
-+ goto out;
-+
-+ len = g_mapped_file_get_length(file);
-+ while (len > 0) {
-+ delim = strchr(contents, '\n');
-+ if (!delim)
-+ delim = contents + len - 1;
-+
-+ if (delim) {
-+ size_t sz = delim - contents;
-+ char *data;
-+
-+ if (delim == contents) {
-+ contents = delim + 1;
-+ len--;
-+ continue;
-+ }
-+
-+ if (!sz)
-+ break;
-+
-+ data = g_strndup(contents, sz);
-+ ret = callback(data);
-+ if (ret) {
-+ g_free(data);
-+ goto out;
-+ }
-+
-+ g_free(data);
-+ contents = delim + 1;
-+ len -= (sz + 1);
-+ }
-+ }
-+
-+ ret = 0;
-+out:
-+ if (file)
-+ g_mapped_file_unref(file);
-+
-+ if (fd) {
-+ g_close(fd, &err);
-+ if (err) {
-+ pr_err("Can't close `%s': %s\n", fname, err->message);
-+ g_error_free(err);
-+ }
-+ }
-+ return ret;
-+}
-+
-+static int init_smbconf_parser(void)
-+{
-+ if (parser.groups)
-+ return 0;
-+
-+ parser.groups = g_hash_table_new(shm_share_name_hash,
-+ shm_share_name_equal);
-+ if (!parser.groups)
-+ return -ENOMEM;
-+ return 0;
-+}
-+
-+static void release_smbconf_group(gpointer k, gpointer v, gpointer user_data)
-+{
-+ struct smbconf_group *g = v;
-+
-+ g_hash_table_destroy(g->kv);
-+ g_free(g->name);
-+ g_free(g);
-+}
-+
-+static void release_smbconf_parser(void)
-+{
-+ if (!parser.groups)
-+ return;
-+
-+ g_hash_table_foreach(parser.groups, release_smbconf_group, NULL);
-+ g_hash_table_destroy(parser.groups);
-+ parser.groups = NULL;
-+}
-+
-+char *cp_ltrim(char *v)
-+{
-+ if (!v)
-+ return NULL;
-+
-+ while (*v && *v == ' ')
-+ v++;
-+ if (*v == 0x00)
-+ return NULL;
-+ return v;
-+}
-+
-+int cp_key_cmp(char *k, char *v)
-+{
-+ if (!k || !v)
-+ return -1;
-+ return g_ascii_strncasecmp(k, v, strlen(v));
-+}
-+
-+char *cp_get_group_kv_string(char *v)
-+{
-+ return g_strdup(v);
-+}
-+
-+int cp_get_group_kv_bool(char *v)
-+{
-+ if (!g_ascii_strncasecmp(v, "yes", 3) ||
-+ !g_ascii_strncasecmp(v, "1", 1) ||
-+ !g_ascii_strncasecmp(v, "true", 4) ||
-+ !g_ascii_strncasecmp(v, "enable", 6))
-+ return 1;
-+ return 0;
-+}
-+
-+int cp_get_group_kv_config_opt(char *v)
-+{
-+ if (!g_ascii_strncasecmp(v, "disabled", 8))
-+ return KSMBD_CONFIG_OPT_DISABLED;
-+ if (!g_ascii_strncasecmp(v, "enabled", 7))
-+ return KSMBD_CONFIG_OPT_ENABLED;
-+ if (!g_ascii_strncasecmp(v, "auto", 4))
-+ return KSMBD_CONFIG_OPT_AUTO;
-+ if (!g_ascii_strncasecmp(v, "mandatory", 9))
-+ return KSMBD_CONFIG_OPT_MANDATORY;
-+ return KSMBD_CONFIG_OPT_DISABLED;
-+}
-+
-+unsigned long cp_get_group_kv_long_base(char *v, int base)
-+{
-+ return strtoul(v, NULL, base);
-+}
-+
-+unsigned long cp_get_group_kv_long(char *v)
-+{
-+ return cp_get_group_kv_long_base(v, 10);
-+}
-+
-+char **cp_get_group_kv_list(char *v)
-+{
-+ /*
-+ * SMB conf lists are "tabs, spaces, commas" separated.
-+ */
-+ return g_strsplit_set(v, "\t ,", -1);
-+}
-+
-+void cp_group_kv_list_free(char **list)
-+{
-+ g_strfreev(list);
-+}
-+
-+static int cp_add_global_guest_account(gpointer _v)
-+{
-+ struct ksmbd_user *user;
-+
-+ if (usm_add_new_user(cp_get_group_kv_string(_v),
-+ g_strdup("NULL"))) {
-+ pr_err("Unable to add guest account\n");
-+ return -ENOMEM;
-+ }
-+
-+ user = usm_lookup_user(_v);
-+ if (!user) {
-+ pr_err("Unable to find user `%s'\n", (char *) _v);
-+ return -EINVAL;
-+ }
-+
-+ set_user_flag(user, KSMBD_USER_FLAG_GUEST_ACCOUNT);
-+ put_ksmbd_user(user);
-+ global_conf.guest_account = cp_get_group_kv_string(_v);
-+ return 0;
-+}
-+
-+static gboolean global_group_kv(gpointer _k, gpointer _v, gpointer user_data)
-+{
-+ if (!cp_key_cmp(_k, "server string")) {
-+ global_conf.server_string = cp_get_group_kv_string(_v);
-+ return TRUE;
-+ }
-+
-+ if (!cp_key_cmp(_k, "workgroup")) {
-+ global_conf.work_group = cp_get_group_kv_string(_v);
-+ return TRUE;
-+ }
-+
-+ if (!cp_key_cmp(_k, "netbios name")) {
-+ global_conf.netbios_name = cp_get_group_kv_string(_v);
-+ return TRUE;
-+ }
-+
-+ if (!cp_key_cmp(_k, "server min protocol")) {
-+ global_conf.server_min_protocol = cp_get_group_kv_string(_v);
-+ return TRUE;
-+ }
-+
-+ if (!cp_key_cmp(_k, "server signing")) {
-+ global_conf.server_signing = cp_get_group_kv_config_opt(_v);
-+ return TRUE;
-+ }
-+
-+ if (!cp_key_cmp(_k, "server max protocol")) {
-+ global_conf.server_max_protocol = cp_get_group_kv_string(_v);
-+ return TRUE;
-+ }
-+
-+ if (!cp_key_cmp(_k, "guest account")) {
-+ cp_add_global_guest_account(_v);
-+ return TRUE;
-+ }
-+
-+ if (!cp_key_cmp(_k, "max active sessions")) {
-+ global_conf.sessions_cap = cp_get_group_kv_long(_v);
-+ return TRUE;
-+ }
-+
-+ if (!cp_key_cmp(_k, "tcp port")) {
-+ if (!global_conf.tcp_port)
-+ global_conf.tcp_port = cp_get_group_kv_long(_v);
-+ return TRUE;
-+ }
-+
-+ if (!cp_key_cmp(_k, "ipc timeout")) {
-+ global_conf.ipc_timeout = cp_get_group_kv_long(_v);
-+ return TRUE;
-+ }
-+
-+ if (!cp_key_cmp(_k, "max open files")) {
-+ global_conf.file_max = cp_get_group_kv_long(_v);
-+ return TRUE;
-+ }
-+
-+ if (!cp_key_cmp(_k, "restrict anonymous")) {
-+ global_conf.restrict_anon = cp_get_group_kv_long(_v);
-+ if (global_conf.restrict_anon > KSMBD_RESTRICT_ANON_TYPE_2 ||
-+ global_conf.restrict_anon < 0) {
-+ global_conf.restrict_anon = 0;
-+ pr_err("Invalid restrict anonymous value\n");
-+ }
-+
-+ return TRUE;
-+ }
-+
-+ if (!cp_key_cmp(_k, "map to guest")) {
-+ global_conf.map_to_guest = KSMBD_CONF_MAP_TO_GUEST_NEVER;
-+ if (!cp_key_cmp(_v, "bad user"))
-+ global_conf.map_to_guest =
-+ KSMBD_CONF_MAP_TO_GUEST_BAD_USER;
-+ if (!cp_key_cmp(_v, "bad password"))
-+ global_conf.map_to_guest =
-+ KSMBD_CONF_MAP_TO_GUEST_BAD_PASSWORD;
-+ if (!cp_key_cmp(_v, "bad uid"))
-+ global_conf.map_to_guest =
-+ KSMBD_CONF_MAP_TO_GUEST_BAD_UID;
-+ return TRUE;
-+ }
-+
-+ if (!cp_key_cmp(_k, "bind interfaces only")) {
-+ global_conf.bind_interfaces_only = cp_get_group_kv_bool(_v);
-+ return TRUE;
-+ }
-+
-+ if (!cp_key_cmp(_k, "interfaces")) {
-+ global_conf.interfaces = cp_get_group_kv_list(_v);
-+ return TRUE;
-+ }
-+
-+ if (!cp_key_cmp(_k, "deadtime")) {
-+ global_conf.deadtime = cp_get_group_kv_long(_v);
-+ return TRUE;
-+ }
-+
-+ if (!cp_key_cmp(_k, "smb2 leases")) {
-+ if (cp_get_group_kv_bool(_v))
-+ global_conf.flags |= KSMBD_GLOBAL_FLAG_SMB2_LEASES;
-+ else
-+ global_conf.flags &= ~KSMBD_GLOBAL_FLAG_SMB2_LEASES;
-+
-+ return TRUE;
-+ }
-+
-+ if (!cp_key_cmp(_k, "root directory")) {
-+ global_conf.root_dir = cp_get_group_kv_string(_v);
-+ return TRUE;
-+ }
-+
-+ if (!cp_key_cmp(_k, "smb2 max read")) {
-+ global_conf.smb2_max_read = memparse(_v);
-+ return TRUE;
-+ }
-+
-+ if (!cp_key_cmp(_k, "smb2 max write")) {
-+ global_conf.smb2_max_write = memparse(_v);
-+ return TRUE;
-+ }
-+
-+ if (!cp_key_cmp(_k, "smb2 max trans")) {
-+ global_conf.smb2_max_trans = memparse(_v);
-+ return TRUE;
-+ }
-+
-+ if (!cp_key_cmp(_k, "smb3 encryption")) {
-+ if (cp_get_group_kv_bool(_v))
-+ global_conf.flags |= KSMBD_GLOBAL_FLAG_SMB3_ENCRYPTION;
-+ else
-+ global_conf.flags &= ~KSMBD_GLOBAL_FLAG_SMB3_ENCRYPTION;
-+
-+ return TRUE;
-+ }
-+
-+ if (!cp_key_cmp(_k, "share:fake_fscaps")) {
-+ global_conf.share_fake_fscaps = cp_get_group_kv_long(_v);
-+ return TRUE;
-+ }
-+
-+ if (!cp_key_cmp(_k, "kerberos service name")) {
-+ global_conf.krb5_service_name = cp_get_group_kv_string(_v);
-+ return TRUE;
-+ }
-+
-+ if (!cp_key_cmp(_k, "kerberos keytab file")) {
-+ global_conf.krb5_keytab_file = cp_get_group_kv_string(_v);
-+ return TRUE;
-+ }
-+
-+ if (!cp_key_cmp(_k, "server multi channel support")) {
-+ if (cp_get_group_kv_bool(_v))
-+ global_conf.flags |= KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL;
-+ else
-+ global_conf.flags &= ~KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL;
-+
-+ return TRUE;
-+ }
-+
-+ if (!cp_key_cmp(_k, "smb2 max credits")) {
-+ global_conf.smb2_max_credits = memparse(_v);
-+ return TRUE;
-+ }
-+
-+ if (!cp_key_cmp(_k, "smbd max io size")) {
-+ global_conf.smbd_max_io_size = memparse(_v);
-+ return TRUE;
-+ }
-+
-+ /* At this point, this is an option that must be applied to all shares */
-+ return FALSE;
-+}
-+
-+static void global_conf_default(void)
-+{
-+ /* The SPARSE_FILES file system capability flag is set by default */
-+ global_conf.share_fake_fscaps = 64;
-+}
-+
-+static void global_conf_create(void)
-+{
-+ if (!global_group || global_group->cb_mode != GROUPS_CALLBACK_INIT)
-+ return;
-+
-+ /*
-+ * This will transfer server options to global_conf, and leave behind
-+ * in the global parser group, the options that must be applied to every
-+ * share
-+ */
-+ g_hash_table_foreach_remove(global_group->kv, global_group_kv, NULL);
-+}
-+
-+static void append_key_value(gpointer _k, gpointer _v, gpointer user_data)
-+{
-+ GHashTable *receiver = (GHashTable *)user_data;
-+
-+ /* Don't override local share options */
-+ if (!g_hash_table_lookup(receiver, _k))
-+ g_hash_table_insert(receiver, g_strdup(_k), g_strdup(_v));
-+}
-+
-+static void global_conf_update(struct smbconf_group *group)
-+{
-+ if (!global_group)
-+ return;
-+
-+ g_hash_table_foreach(global_group->kv, append_key_value, group->kv);
-+}
-+
-+static void global_conf_fixup_missing(void)
-+{
-+ /*
-+ * Set default global parameters which were not specified
-+ * in smb.conf
-+ */
-+ if (!global_conf.file_max)
-+ global_conf.file_max = KSMBD_CONF_FILE_MAX;
-+ if (!global_conf.server_string)
-+ global_conf.server_string =
-+ cp_get_group_kv_string(
-+ KSMBD_CONF_DEFAULT_SERVER_STRING);
-+ if (!global_conf.netbios_name)
-+ global_conf.netbios_name =
-+ cp_get_group_kv_string(KSMBD_CONF_DEFAULT_NETBIOS_NAME);
-+ if (!global_conf.work_group)
-+ global_conf.work_group =
-+ cp_get_group_kv_string(KSMBD_CONF_DEFAULT_WORK_GROUP);
-+ if (!global_conf.tcp_port)
-+ global_conf.tcp_port = KSMBD_CONF_DEFAULT_TCP_PORT;
-+
-+ if (global_conf.sessions_cap <= 0)
-+ global_conf.sessions_cap = KSMBD_CONF_DEFAULT_SESS_CAP;
-+
-+ if (!global_conf.guest_account &&
-+ cp_add_global_guest_account(KSMBD_CONF_DEFAULT_GUEST_ACCOUNT))
-+ pr_err("Unable to add guest account\n");
-+}
-+
-+static void groups_callback(gpointer _k, gpointer _v, gpointer user_data)
-+{
-+ struct smbconf_group *group = (struct smbconf_group *)_v;
-+ unsigned short cb_mode = *(unsigned short *)user_data;
-+
-+ if (group == global_group)
-+ return;
-+
-+ group->cb_mode = cb_mode;
-+
-+ if (group != ipc_group)
-+ global_conf_update(group);
-+
-+ shm_add_new_share(group);
-+}
-+
-+static int cp_add_ipc_group(void)
-+{
-+ char *comment = NULL, *guest = NULL;
-+ int ret = 0;
-+
-+ if (ipc_group)
-+ return ret;
-+
-+ comment = g_strdup("comment = IPC share");
-+ guest = g_strdup("guest ok = yes");
-+ ret = add_new_group("[IPC$]");
-+ ret |= add_group_key_value(comment);
-+ ret |= add_group_key_value(guest);
-+ if (ret) {
-+ pr_err("Unable to add IPC$ share\n");
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ ipc_group = g_hash_table_lookup(parser.groups, "ipc$");
-+out:
-+ g_free(comment);
-+ g_free(guest);
-+ return ret;
-+}
-+
-+static int __cp_parse_smbconfig(const char *smbconf, GHFunc cb,
-+ unsigned short cb_mode)
-+{
-+ int ret;
-+
-+ global_conf_default();
-+
-+ ret = cp_smbconfig_hash_create(smbconf);
-+ if (ret)
-+ return ret;
-+
-+ ret = cp_add_ipc_group();
-+ if (ret)
-+ goto out;
-+
-+ global_group = g_hash_table_lookup(parser.groups, "global");
-+ if (global_group)
-+ global_group->cb_mode = cb_mode;
-+
-+ global_conf_create();
-+ g_hash_table_foreach(parser.groups, groups_callback, &cb_mode);
-+ global_conf_fixup_missing();
-+out:
-+ cp_smbconfig_destroy();
-+ return ret;
-+}
-+
-+int cp_parse_reload_smbconf(const char *smbconf)
-+{
-+ return __cp_parse_smbconfig(smbconf, groups_callback,
-+ GROUPS_CALLBACK_REINIT);
-+}
-+
-+int cp_parse_smbconf(const char *smbconf)
-+{
-+ return __cp_parse_smbconfig(smbconf, groups_callback,
-+ GROUPS_CALLBACK_INIT);
-+}
-+
-+int cp_parse_pwddb(const char *pwddb)
-+{
-+ return __mmap_parse_file(pwddb, usm_add_update_user_from_pwdentry);
-+}
-+
-+int cp_smbconfig_hash_create(const char *smbconf)
-+{
-+ int ret = init_smbconf_parser();
-+
-+ if (ret)
-+ return ret;
-+ return __mmap_parse_file(smbconf, process_smbconf_entry);
-+}
-+
-+int cp_parse_subauth(void)
-+{
-+ return __mmap_parse_file(PATH_SUBAUTH, usm_add_subauth_global_conf);
-+}
-+
-+void cp_smbconfig_destroy(void)
-+{
-+ release_smbconf_parser();
-+}
-+
-+int cp_parse_external_smbconf_group(char *name, char *opts)
-+{
-+ char *pos;
-+ int i, len;
-+
-+ if (init_smbconf_parser())
-+ return -EINVAL;
-+
-+ if (!opts || !name)
-+ return -EINVAL;
-+
-+ len = strlen(opts);
-+ /* fake smb.conf input */
-+ for (i = 0; i < KSMBD_SHARE_CONF_MAX; i++) {
-+ pos = strstr(opts, KSMBD_SHARE_CONF[i]);
-+ if (!pos)
-+ continue;
-+ if (pos != opts)
-+ *(pos - 1) = '\n';
-+ }
-+
-+ if (add_new_group(name))
-+ goto error;
-+
-+ /* split input and feed to normal process_smbconf_entry() */
-+ while (len) {
-+ char *delim = strchr(opts, '\n');
-+
-+ if (delim) {
-+ *delim = 0x00;
-+ len -= delim - opts;
-+ } else {
-+ len = 0;
-+ }
-+
-+ process_smbconf_entry(opts);
-+ if (delim)
-+ opts = delim + 1;
-+ }
-+ return 0;
-+
-+error:
-+ cp_smbconfig_destroy();
-+ return -EINVAL;
-+}
---- a/lib/management/session.c
-+++ /dev/null
-@@ -1,235 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0-or-later
--/*
-- * Copyright (C) 2018 Samsung Electronics Co., Ltd.
-- *
-- * linux-cifsd-devel@lists.sourceforge.net
-- */
--
--#include <stdlib.h>
--#include <string.h>
--#include <glib.h>
--
--#include "linux/ksmbd_server.h"
--#include "management/session.h"
--#include "management/tree_conn.h"
--#include "management/user.h"
--#include "ksmbdtools.h"
--
--static GHashTable *sessions_table;
--static GRWLock sessions_table_lock;
--
--static void __free_func(gpointer data, gpointer user_data)
--{
-- struct ksmbd_tree_conn *tree_conn;
--
-- tree_conn = (struct ksmbd_tree_conn *)data;
-- tcm_tree_conn_free(tree_conn);
--}
--
--static void kill_ksmbd_session(struct ksmbd_session *sess)
--{
-- g_list_foreach(sess->tree_conns, __free_func, NULL);
-- g_list_free(sess->tree_conns);
-- g_rw_lock_clear(&sess->update_lock);
-- g_free(sess);
--}
--
--static struct ksmbd_session *new_ksmbd_session(unsigned long long id,
-- struct ksmbd_user *user)
--{
-- struct ksmbd_session *sess;
--
-- sess = g_try_malloc0(sizeof(struct ksmbd_session));
-- if (!sess)
-- return NULL;
--
-- g_rw_lock_init(&sess->update_lock);
-- sess->ref_counter = 1;
-- sess->id = id;
-- sess->user = user;
-- return sess;
--}
--
--static void free_hash_entry(gpointer k, gpointer s, gpointer user_data)
--{
-- kill_ksmbd_session(s);
--}
--
--static void sm_clear_sessions(void)
--{
-- g_hash_table_foreach(sessions_table, free_hash_entry, NULL);
--}
--
--static int __sm_remove_session(struct ksmbd_session *sess)
--{
-- int ret = -EINVAL;
--
-- g_rw_lock_writer_lock(&sessions_table_lock);
-- if (g_hash_table_remove(sessions_table, &sess->id))
-- ret = 0;
-- g_rw_lock_writer_unlock(&sessions_table_lock);
--
-- if (!ret)
-- kill_ksmbd_session(sess);
-- return ret;
--}
--
--static struct ksmbd_session *__get_session(struct ksmbd_session *sess)
--{
-- struct ksmbd_session *ret = NULL;
--
-- g_rw_lock_writer_lock(&sess->update_lock);
-- if (sess->ref_counter != 0) {
-- sess->ref_counter++;
-- ret = sess;
-- } else {
-- ret = NULL;
-- }
-- g_rw_lock_writer_unlock(&sess->update_lock);
-- return ret;
--}
--
--static void __put_session(struct ksmbd_session *sess)
--{
-- int drop = 0;
--
-- g_rw_lock_writer_lock(&sess->update_lock);
-- sess->ref_counter--;
-- drop = !sess->ref_counter;
-- g_rw_lock_writer_unlock(&sess->update_lock);
--
-- if (drop)
-- __sm_remove_session(sess);
--}
--
--static struct ksmbd_session *__sm_lookup_session(unsigned long long id)
--{
-- return g_hash_table_lookup(sessions_table, &id);
--}
--
--static struct ksmbd_session *sm_lookup_session(unsigned long long id)
--{
-- struct ksmbd_session *sess;
--
-- g_rw_lock_reader_lock(&sessions_table_lock);
-- sess = __sm_lookup_session(id);
-- if (sess)
-- sess = __get_session(sess);
-- g_rw_lock_reader_unlock(&sessions_table_lock);
-- return sess;
--}
--
--int sm_handle_tree_connect(unsigned long long id,
-- struct ksmbd_user *user,
-- struct ksmbd_tree_conn *tree_conn)
--{
-- struct ksmbd_session *sess, *lookup;
--
--retry:
-- sess = sm_lookup_session(id);
-- if (!sess) {
-- sess = new_ksmbd_session(id, user);
-- if (!sess)
-- return -EINVAL;
--
-- g_rw_lock_writer_lock(&sessions_table_lock);
-- lookup = __sm_lookup_session(id);
-- if (lookup)
-- lookup = __get_session(lookup);
-- if (lookup) {
-- kill_ksmbd_session(sess);
-- sess = lookup;
-- }
-- if (!g_hash_table_insert(sessions_table, &(sess->id), sess)) {
-- kill_ksmbd_session(sess);
-- sess = NULL;
-- }
-- g_rw_lock_writer_unlock(&sessions_table_lock);
--
-- if (!sess)
-- goto retry;
-- }
--
-- g_rw_lock_writer_lock(&sess->update_lock);
-- sess->tree_conns = g_list_insert(sess->tree_conns, tree_conn, -1);
-- g_rw_lock_writer_unlock(&sess->update_lock);
-- return 0;
--}
--
--int sm_check_sessions_capacity(unsigned long long id)
--{
-- int ret = 0;
-- struct ksmbd_session *sess;
--
-- sess = sm_lookup_session(id);
-- if (sess) {
-- __put_session(sess);
-- return ret;
-- }
--
-- if (g_atomic_int_add(&global_conf.sessions_cap, -1) < 1) {
-- ret = -EINVAL;
-- g_atomic_int_inc(&global_conf.sessions_cap);
-- }
-- return ret;
--}
--
--static gint lookup_tree_conn(gconstpointer data, gconstpointer user_data)
--{
-- struct ksmbd_tree_conn *tree_conn = (struct ksmbd_tree_conn *)data;
-- struct ksmbd_tree_conn *dummy = (struct ksmbd_tree_conn *)user_data;
--
-- if (tree_conn->id == dummy->id)
-- return 0;
-- return 1;
--}
--
--int sm_handle_tree_disconnect(unsigned long long sess_id,
-- unsigned long long tree_conn_id)
--{
-- struct ksmbd_tree_conn dummy;
-- struct ksmbd_session *sess;
-- GList *tc_list;
--
-- sess = sm_lookup_session(sess_id);
-- if (!sess)
-- return 0;
--
-- g_atomic_int_inc(&global_conf.sessions_cap);
-- g_rw_lock_writer_lock(&sess->update_lock);
-- dummy.id = tree_conn_id;
-- tc_list = g_list_find_custom(sess->tree_conns,
-- &dummy,
-- lookup_tree_conn);
-- if (tc_list) {
-- struct ksmbd_tree_conn *tree_conn;
--
-- tree_conn = (struct ksmbd_tree_conn *)tc_list->data;
-- sess->tree_conns = g_list_remove(sess->tree_conns, tree_conn);
-- sess->ref_counter--;
-- tcm_tree_conn_free(tree_conn);
-- }
-- g_rw_lock_writer_unlock(&sess->update_lock);
--
-- put_ksmbd_user(sess->user);
-- __put_session(sess);
-- return 0;
--}
--
--void sm_destroy(void)
--{
-- if (sessions_table) {
-- sm_clear_sessions();
-- g_hash_table_destroy(sessions_table);
-- }
-- g_rw_lock_clear(&sessions_table_lock);
--}
--
--int sm_init(void)
--{
-- sessions_table = g_hash_table_new(g_int64_hash, g_int64_equal);
-- if (!sessions_table)
-- return -ENOMEM;
-- g_rw_lock_init(&sessions_table_lock);
-- return 0;
--}
---- /dev/null
-+++ b/tools/management/session.c
-@@ -0,0 +1,235 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+/*
-+ * Copyright (C) 2018 Samsung Electronics Co., Ltd.
-+ *
-+ * linux-cifsd-devel@lists.sourceforge.net
-+ */
-+
-+#include <stdlib.h>
-+#include <string.h>
-+#include <glib.h>
-+
-+#include "linux/ksmbd_server.h"
-+#include "management/session.h"
-+#include "management/tree_conn.h"
-+#include "management/user.h"
-+#include "tools.h"
-+
-+static GHashTable *sessions_table;
-+static GRWLock sessions_table_lock;
-+
-+static void __free_func(gpointer data, gpointer user_data)
-+{
-+ struct ksmbd_tree_conn *tree_conn;
-+
-+ tree_conn = (struct ksmbd_tree_conn *)data;
-+ tcm_tree_conn_free(tree_conn);
-+}
-+
-+static void kill_ksmbd_session(struct ksmbd_session *sess)
-+{
-+ g_list_foreach(sess->tree_conns, __free_func, NULL);
-+ g_list_free(sess->tree_conns);
-+ g_rw_lock_clear(&sess->update_lock);
-+ g_free(sess);
-+}
-+
-+static struct ksmbd_session *new_ksmbd_session(unsigned long long id,
-+ struct ksmbd_user *user)
-+{
-+ struct ksmbd_session *sess;
-+
-+ sess = g_try_malloc0(sizeof(struct ksmbd_session));
-+ if (!sess)
-+ return NULL;
-+
-+ g_rw_lock_init(&sess->update_lock);
-+ sess->ref_counter = 1;
-+ sess->id = id;
-+ sess->user = user;
-+ return sess;
-+}
-+
-+static void free_hash_entry(gpointer k, gpointer s, gpointer user_data)
-+{
-+ kill_ksmbd_session(s);
-+}
-+
-+static void sm_clear_sessions(void)
-+{
-+ g_hash_table_foreach(sessions_table, free_hash_entry, NULL);
-+}
-+
-+static int __sm_remove_session(struct ksmbd_session *sess)
-+{
-+ int ret = -EINVAL;
-+
-+ g_rw_lock_writer_lock(&sessions_table_lock);
-+ if (g_hash_table_remove(sessions_table, &sess->id))
-+ ret = 0;
-+ g_rw_lock_writer_unlock(&sessions_table_lock);
-+
-+ if (!ret)
-+ kill_ksmbd_session(sess);
-+ return ret;
-+}
-+
-+static struct ksmbd_session *__get_session(struct ksmbd_session *sess)
-+{
-+ struct ksmbd_session *ret = NULL;
-+
-+ g_rw_lock_writer_lock(&sess->update_lock);
-+ if (sess->ref_counter != 0) {
-+ sess->ref_counter++;
-+ ret = sess;
-+ } else {
-+ ret = NULL;
-+ }
-+ g_rw_lock_writer_unlock(&sess->update_lock);
-+ return ret;
-+}
-+
-+static void __put_session(struct ksmbd_session *sess)
-+{
-+ int drop = 0;
-+
-+ g_rw_lock_writer_lock(&sess->update_lock);
-+ sess->ref_counter--;
-+ drop = !sess->ref_counter;
-+ g_rw_lock_writer_unlock(&sess->update_lock);
-+
-+ if (drop)
-+ __sm_remove_session(sess);
-+}
-+
-+static struct ksmbd_session *__sm_lookup_session(unsigned long long id)
-+{
-+ return g_hash_table_lookup(sessions_table, &id);
-+}
-+
-+static struct ksmbd_session *sm_lookup_session(unsigned long long id)
-+{
-+ struct ksmbd_session *sess;
-+
-+ g_rw_lock_reader_lock(&sessions_table_lock);
-+ sess = __sm_lookup_session(id);
-+ if (sess)
-+ sess = __get_session(sess);
-+ g_rw_lock_reader_unlock(&sessions_table_lock);
-+ return sess;
-+}
-+
-+int sm_handle_tree_connect(unsigned long long id,
-+ struct ksmbd_user *user,
-+ struct ksmbd_tree_conn *tree_conn)
-+{
-+ struct ksmbd_session *sess, *lookup;
-+
-+retry:
-+ sess = sm_lookup_session(id);
-+ if (!sess) {
-+ sess = new_ksmbd_session(id, user);
-+ if (!sess)
-+ return -EINVAL;
-+
-+ g_rw_lock_writer_lock(&sessions_table_lock);
-+ lookup = __sm_lookup_session(id);
-+ if (lookup)
-+ lookup = __get_session(lookup);
-+ if (lookup) {
-+ kill_ksmbd_session(sess);
-+ sess = lookup;
-+ }
-+ if (!g_hash_table_insert(sessions_table, &(sess->id), sess)) {
-+ kill_ksmbd_session(sess);
-+ sess = NULL;
-+ }
-+ g_rw_lock_writer_unlock(&sessions_table_lock);
-+
-+ if (!sess)
-+ goto retry;
-+ }
-+
-+ g_rw_lock_writer_lock(&sess->update_lock);
-+ sess->tree_conns = g_list_insert(sess->tree_conns, tree_conn, -1);
-+ g_rw_lock_writer_unlock(&sess->update_lock);
-+ return 0;
-+}
-+
-+int sm_check_sessions_capacity(unsigned long long id)
-+{
-+ int ret = 0;
-+ struct ksmbd_session *sess;
-+
-+ sess = sm_lookup_session(id);
-+ if (sess) {
-+ __put_session(sess);
-+ return ret;
-+ }
-+
-+ if (g_atomic_int_add(&global_conf.sessions_cap, -1) < 1) {
-+ ret = -EINVAL;
-+ g_atomic_int_inc(&global_conf.sessions_cap);
-+ }
-+ return ret;
-+}
-+
-+static gint lookup_tree_conn(gconstpointer data, gconstpointer user_data)
-+{
-+ struct ksmbd_tree_conn *tree_conn = (struct ksmbd_tree_conn *)data;
-+ struct ksmbd_tree_conn *dummy = (struct ksmbd_tree_conn *)user_data;
-+
-+ if (tree_conn->id == dummy->id)
-+ return 0;
-+ return 1;
-+}
-+
-+int sm_handle_tree_disconnect(unsigned long long sess_id,
-+ unsigned long long tree_conn_id)
-+{
-+ struct ksmbd_tree_conn dummy;
-+ struct ksmbd_session *sess;
-+ GList *tc_list;
-+
-+ sess = sm_lookup_session(sess_id);
-+ if (!sess)
-+ return 0;
-+
-+ g_atomic_int_inc(&global_conf.sessions_cap);
-+ g_rw_lock_writer_lock(&sess->update_lock);
-+ dummy.id = tree_conn_id;
-+ tc_list = g_list_find_custom(sess->tree_conns,
-+ &dummy,
-+ lookup_tree_conn);
-+ if (tc_list) {
-+ struct ksmbd_tree_conn *tree_conn;
-+
-+ tree_conn = (struct ksmbd_tree_conn *)tc_list->data;
-+ sess->tree_conns = g_list_remove(sess->tree_conns, tree_conn);
-+ sess->ref_counter--;
-+ tcm_tree_conn_free(tree_conn);
-+ }
-+ g_rw_lock_writer_unlock(&sess->update_lock);
-+
-+ put_ksmbd_user(sess->user);
-+ __put_session(sess);
-+ return 0;
-+}
-+
-+void sm_destroy(void)
-+{
-+ if (sessions_table) {
-+ sm_clear_sessions();
-+ g_hash_table_destroy(sessions_table);
-+ }
-+ g_rw_lock_clear(&sessions_table_lock);
-+}
-+
-+int sm_init(void)
-+{
-+ sessions_table = g_hash_table_new(g_int64_hash, g_int64_equal);
-+ if (!sessions_table)
-+ return -ENOMEM;
-+ g_rw_lock_init(&sessions_table_lock);
-+ return 0;
-+}
---- a/lib/management/share.c
-+++ /dev/null
-@@ -1,868 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0-or-later
--/*
-- * Copyright (C) 2018 Samsung Electronics Co., Ltd.
-- *
-- * linux-cifsd-devel@lists.sourceforge.net
-- */
--
--#include <stdlib.h>
--#include <string.h>
--#include <glib.h>
--#include <sys/types.h>
--#include <pwd.h>
--#include <grp.h>
--
--#include "config_parser.h"
--#include "linux/ksmbd_server.h"
--#include "management/share.h"
--#include "management/user.h"
--#include "ksmbdtools.h"
--
--#define KSMBD_SHARE_STATE_FREEING 1
--
--/*
-- * WARNING:
-- *
-- * This must match KSMBD_SHARE_CONF enum 1:1.
-- * Add new entries ONLY to the bottom.
-- */
--char *KSMBD_SHARE_CONF[KSMBD_SHARE_CONF_MAX] = {
-- "comment", /* 0 */
-- "path",
-- "guest ok",
-- "guest account",
-- "read only",
-- "browseable", /* 5 */
-- "write ok",
-- "writeable",
-- "store dos attributes",
-- "oplocks",
-- "create mask", /* 10 */
-- "directory mask",
-- "force create mode",
-- "force directory mode",
-- "force group",
-- "force user", /* 15 */
-- "hide dot files",
-- "valid users",
-- "invalid users",
-- "read list",
-- "write list", /* 20 */
-- "admin users",
-- "hosts allow",
-- "hosts deny",
-- "max connections",
-- "veto files", /* 25 */
-- "inherit owner",
-- "follow symlinks",
-- "vfs objects",
-- "writable",
--};
--
--static GHashTable *shares_table;
--static GRWLock shares_table_lock;
--
--int shm_share_config(char *k, enum KSMBD_SHARE_CONF c)
--{
-- if (c >= KSMBD_SHARE_CONF_MAX)
-- return 0;
--
-- return !cp_key_cmp(k, KSMBD_SHARE_CONF[c]);
--}
--
--static void list_hosts_callback(gpointer k, gpointer v, gpointer user_data)
--{
-- free(k);
-- free(v);
--}
--
--static void free_hosts_map(GHashTable *map)
--{
-- if (map) {
-- g_hash_table_foreach(map, list_hosts_callback, NULL);
-- g_hash_table_destroy(map);
-- }
--}
--
--static void list_user_callback(gpointer k, gpointer u, gpointer user_data)
--{
-- put_ksmbd_user((struct ksmbd_user *)u);
--}
--
--static void free_user_map(GHashTable *map)
--{
-- if (map) {
-- g_hash_table_foreach(map, list_user_callback, NULL);
-- g_hash_table_destroy(map);
-- }
--}
--
--static void kill_ksmbd_share(struct ksmbd_share *share)
--{
-- int i;
--
-- pr_debug("Kill share `%s'\n", share->name);
--
-- for (i = 0; i < KSMBD_SHARE_USERS_MAX; i++)
-- free_user_map(share->maps[i]);
--
-- free_hosts_map(share->hosts_allow_map);
-- free_hosts_map(share->hosts_deny_map);
--
-- g_rw_lock_clear(&share->maps_lock);
--
-- free(share->name);
-- free(share->path);
-- free(share->comment);
-- free(share->veto_list);
-- free(share->guest_account);
-- g_rw_lock_clear(&share->update_lock);
-- g_free(share);
--}
--
--static int __shm_remove_share(struct ksmbd_share *share)
--{
-- int ret = 0;
--
-- if (share->state != KSMBD_SHARE_STATE_FREEING) {
-- g_rw_lock_writer_lock(&shares_table_lock);
-- if (!g_hash_table_remove(shares_table, share->name))
-- ret = -EINVAL;
-- g_rw_lock_writer_unlock(&shares_table_lock);
-- }
-- if (!ret)
-- kill_ksmbd_share(share);
-- return ret;
--}
--
--struct ksmbd_share *get_ksmbd_share(struct ksmbd_share *share)
--{
-- g_rw_lock_writer_lock(&share->update_lock);
-- if (share->ref_count != 0) {
-- share->ref_count++;
-- g_rw_lock_writer_unlock(&share->update_lock);
-- } else {
-- g_rw_lock_writer_unlock(&share->update_lock);
-- share = NULL;
-- }
--
-- return share;
--}
--
--void put_ksmbd_share(struct ksmbd_share *share)
--{
-- int drop;
--
-- if (!share)
-- return;
--
-- g_rw_lock_writer_lock(&share->update_lock);
-- share->ref_count--;
-- drop = !share->ref_count;
-- g_rw_lock_writer_unlock(&share->update_lock);
--
-- if (!drop)
-- return;
--
-- __shm_remove_share(share);
--}
--
--static gboolean put_share_callback(gpointer _k, gpointer _v, gpointer data)
--{
-- struct ksmbd_share *share = (struct ksmbd_share *)_v;
--
-- share->state = KSMBD_SHARE_STATE_FREEING;
-- put_ksmbd_share(share);
-- return TRUE;
--}
--
--void shm_remove_all_shares(void)
--{
-- g_rw_lock_writer_lock(&shares_table_lock);
-- g_hash_table_foreach_remove(shares_table, put_share_callback, NULL);
-- g_rw_lock_writer_unlock(&shares_table_lock);
--}
--
--static struct ksmbd_share *new_ksmbd_share(void)
--{
-- struct ksmbd_share *share;
-- int i;
--
-- share = g_try_malloc0(sizeof(struct ksmbd_share));
-- if (!share)
-- return NULL;
--
-- share->ref_count = 1;
-- /*
-- * Create maps as needed. NULL maps means that share
-- * does not have a corresponding shmbconf entry.
-- */
-- for (i = 0; i < KSMBD_SHARE_USERS_MAX; i++)
-- share->maps[i] = NULL;
--
-- share->hosts_allow_map = NULL;
-- share->hosts_deny_map = NULL;
-- g_rw_lock_init(&share->maps_lock);
-- g_rw_lock_init(&share->update_lock);
--
-- return share;
--}
--
--static void free_hash_entry(gpointer k, gpointer s, gpointer user_data)
--{
-- kill_ksmbd_share(s);
--}
--
--static void shm_clear_shares(void)
--{
-- g_hash_table_foreach(shares_table, free_hash_entry, NULL);
--}
--
--void shm_destroy(void)
--{
-- if (shares_table) {
-- shm_clear_shares();
-- g_hash_table_destroy(shares_table);
-- }
-- g_rw_lock_clear(&shares_table_lock);
--}
--
--static char *shm_casefold_share_name(const char *name, size_t len)
--{
-- char *nfdi_name, *nfdicf_name;
--
-- nfdi_name = g_utf8_normalize(name, len, G_NORMALIZE_NFD);
-- if (!nfdi_name)
-- goto out_ascii;
--
-- nfdicf_name = g_utf8_casefold(nfdi_name, strlen(nfdi_name));
-- g_free(nfdi_name);
-- return nfdicf_name;
--out_ascii:
-- g_free(nfdi_name);
-- return g_ascii_strdown(name, len);
--}
--
--guint shm_share_name_hash(gconstpointer name)
--{
-- char *cf_name;
-- guint hash;
--
-- cf_name = shm_casefold_share_name(name, strlen(name));
-- hash = g_str_hash(cf_name);
-- g_free(cf_name);
-- return hash;
--}
--
--gboolean shm_share_name_equal(gconstpointer lname, gconstpointer rname)
--{
-- char *cf_lname, *cf_rname;
-- gboolean equal;
--
-- cf_lname = shm_casefold_share_name(lname, strlen(lname));
-- cf_rname = shm_casefold_share_name(rname, strlen(rname));
-- equal = g_str_equal(cf_lname, cf_rname);
-- g_free(cf_lname);
-- g_free(cf_rname);
-- return equal;
--}
--
--int shm_init(void)
--{
-- shares_table = g_hash_table_new(shm_share_name_hash,
-- shm_share_name_equal);
-- if (!shares_table)
-- return -ENOMEM;
-- g_rw_lock_init(&shares_table_lock);
-- return 0;
--}
--
--static struct ksmbd_share *__shm_lookup_share(char *name)
--{
-- return g_hash_table_lookup(shares_table, name);
--}
--
--struct ksmbd_share *shm_lookup_share(char *name)
--{
-- struct ksmbd_share *share, *ret;
--
-- g_rw_lock_reader_lock(&shares_table_lock);
-- share = __shm_lookup_share(name);
-- if (share) {
-- ret = get_ksmbd_share(share);
-- if (!ret)
-- share = NULL;
-- }
-- g_rw_lock_reader_unlock(&shares_table_lock);
-- return share;
--}
--
--static GHashTable *parse_list(GHashTable *map, char **list, char grc)
--{
-- int i;
--
-- if (!list)
-- return map;
--
-- if (!map)
-- map = g_hash_table_new(g_str_hash, g_str_equal);
-- if (!map)
-- return map;
--
-- for (i = 0; list[i] != NULL; i++) {
-- struct ksmbd_user *user;
-- char *p = list[i];
--
-- p = cp_ltrim(p);
-- if (!p)
-- continue;
--
-- if (*p == grc) {
-- struct group *gr;
--
-- gr = getgrnam(p + 1);
-- if (gr)
-- parse_list(map, gr->gr_mem, 0x00);
-- continue;
-- }
--
-- user = usm_lookup_user(p);
-- if (!user) {
-- pr_info("Drop non-existing user `%s'\n", p);
-- continue;
-- }
--
-- if (g_hash_table_lookup(map, user->name)) {
-- pr_debug("User `%s' already exists in a map\n",
-- user->name);
-- continue;
-- }
--
-- g_hash_table_insert(map, user->name, user);
-- }
--
-- return map;
--}
--
--static void make_veto_list(struct ksmbd_share *share)
--{
-- int i;
--
-- for (i = 0; i < share->veto_list_sz; i++) {
-- if (share->veto_list[i] == '/')
-- share->veto_list[i] = 0x00;
-- }
--}
--
--static void force_group(struct ksmbd_share *share, char *name)
--{
-- struct group *grp;
--
-- grp = getgrnam(name);
-- if (grp) {
-- share->force_gid = grp->gr_gid;
-- if (share->force_gid == KSMBD_SHARE_INVALID_GID)
-- pr_err("Invalid force GID: %u\n", share->force_gid);
-- } else
-- pr_err("Unable to lookup up `/etc/group' entry: %s\n", name);
--}
--
--static void force_user(struct ksmbd_share *share, char *name)
--{
-- struct passwd *passwd;
--
-- passwd = getpwnam(name);
-- if (passwd) {
-- share->force_uid = passwd->pw_uid;
-- /*
-- * smb.conf 'force group' has higher priority than
-- * 'force user'.
-- */
-- if (share->force_gid == KSMBD_SHARE_INVALID_GID)
-- share->force_gid = passwd->pw_gid;
-- if (share->force_uid == KSMBD_SHARE_INVALID_UID ||
-- share->force_gid == KSMBD_SHARE_INVALID_GID)
-- pr_err("Invalid force UID/GID: %u/%u\n",
-- share->force_uid, share->force_gid);
-- } else {
-- pr_err("Unable to lookup up `/etc/passwd' entry: %s\n", name);
-- }
--}
--
--static void process_group_kv(gpointer _k, gpointer _v, gpointer user_data)
--{
-- struct ksmbd_share *share = user_data;
-- char *k = _k;
-- char *v = _v;
--
-- if (shm_share_config(k, KSMBD_SHARE_CONF_COMMENT)) {
-- share->comment = cp_get_group_kv_string(v);
-- if (share->comment == NULL)
-- set_share_flag(share, KSMBD_SHARE_FLAG_INVALID);
-- return;
-- }
--
-- if (shm_share_config(k, KSMBD_SHARE_CONF_PATH)) {
-- share->path = cp_get_group_kv_string(v);
-- if (share->path == NULL)
-- set_share_flag(share, KSMBD_SHARE_FLAG_INVALID);
-- return;
-- }
--
-- if (shm_share_config(k, KSMBD_SHARE_CONF_GUEST_OK)) {
-- if (cp_get_group_kv_bool(v))
-- set_share_flag(share, KSMBD_SHARE_FLAG_GUEST_OK);
-- return;
-- }
--
-- if (shm_share_config(k, KSMBD_SHARE_CONF_GUEST_ACCOUNT)) {
-- struct ksmbd_user *user;
--
-- if (usm_add_new_user(cp_get_group_kv_string(_v),
-- g_strdup("NULL"))) {
-- pr_err("Unable to add guest account\n");
-- set_share_flag(share, KSMBD_SHARE_FLAG_INVALID);
-- return;
-- }
--
-- user = usm_lookup_user(_v);
-- if (user) {
-- set_user_flag(user, KSMBD_USER_FLAG_GUEST_ACCOUNT);
-- put_ksmbd_user(user);
-- }
-- share->guest_account = cp_get_group_kv_string(_v);
-- if (!share->guest_account)
-- set_share_flag(share, KSMBD_SHARE_FLAG_INVALID);
-- return;
-- }
--
-- if (shm_share_config(k, KSMBD_SHARE_CONF_READ_ONLY)) {
-- if (cp_get_group_kv_bool(v)) {
-- set_share_flag(share, KSMBD_SHARE_FLAG_READONLY);
-- clear_share_flag(share, KSMBD_SHARE_FLAG_WRITEABLE);
-- } else {
-- clear_share_flag(share, KSMBD_SHARE_FLAG_READONLY);
-- set_share_flag(share, KSMBD_SHARE_FLAG_WRITEABLE);
-- }
-- return;
-- }
--
-- if (shm_share_config(k, KSMBD_SHARE_CONF_BROWSEABLE)) {
-- if (cp_get_group_kv_bool(v))
-- set_share_flag(share, KSMBD_SHARE_FLAG_BROWSEABLE);
-- else
-- clear_share_flag(share, KSMBD_SHARE_FLAG_BROWSEABLE);
-- return;
-- }
--
-- if (shm_share_config(k, KSMBD_SHARE_CONF_WRITE_OK) ||
-- shm_share_config(k, KSMBD_SHARE_CONF_WRITEABLE) ||
-- shm_share_config(k, KSMBD_SHARE_CONF_WRITABLE)) {
-- if (cp_get_group_kv_bool(v))
-- set_share_flag(share, KSMBD_SHARE_FLAG_WRITEABLE);
-- else
-- clear_share_flag(share, KSMBD_SHARE_FLAG_WRITEABLE);
-- return;
-- }
--
-- if (shm_share_config(k, KSMBD_SHARE_CONF_STORE_DOS_ATTRIBUTES)) {
-- if (cp_get_group_kv_bool(v))
-- set_share_flag(share, KSMBD_SHARE_FLAG_STORE_DOS_ATTRS);
-- else
-- clear_share_flag(share,
-- KSMBD_SHARE_FLAG_STORE_DOS_ATTRS);
-- return;
-- }
--
-- if (shm_share_config(k, KSMBD_SHARE_CONF_OPLOCKS)) {
-- if (cp_get_group_kv_bool(v))
-- set_share_flag(share, KSMBD_SHARE_FLAG_OPLOCKS);
-- else
-- clear_share_flag(share, KSMBD_SHARE_FLAG_OPLOCKS);
-- return;
-- }
--
-- if (shm_share_config(k, KSMBD_SHARE_CONF_CREATE_MASK)) {
-- share->create_mask = cp_get_group_kv_long_base(v, 8);
-- return;
-- }
--
-- if (shm_share_config(k, KSMBD_SHARE_CONF_DIRECTORY_MASK)) {
-- share->directory_mask = cp_get_group_kv_long_base(v, 8);
-- return;
-- }
--
-- if (shm_share_config(k, KSMBD_SHARE_CONF_FORCE_CREATE_MODE)) {
-- share->force_create_mode = cp_get_group_kv_long_base(v, 8);
-- return;
-- }
--
-- if (shm_share_config(k, KSMBD_SHARE_CONF_FORCE_DIRECTORY_MODE)) {
-- share->force_directory_mode = cp_get_group_kv_long_base(v, 8);
-- return;
-- }
--
-- if (shm_share_config(k, KSMBD_SHARE_CONF_FORCE_GROUP)) {
-- force_group(share, v);
-- return;
-- }
--
-- if (shm_share_config(k, KSMBD_SHARE_CONF_FORCE_USER)) {
-- force_user(share, v);
-- return;
-- }
--
-- if (shm_share_config(k, KSMBD_SHARE_CONF_HIDE_DOT_FILES)) {
-- if (cp_get_group_kv_bool(v))
-- set_share_flag(share, KSMBD_SHARE_FLAG_HIDE_DOT_FILES);
-- else
-- clear_share_flag(share,
-- KSMBD_SHARE_FLAG_HIDE_DOT_FILES);
-- }
--
-- if (shm_share_config(k, KSMBD_SHARE_CONF_VALID_USERS)) {
-- char **users_list;
--
-- users_list = cp_get_group_kv_list(v);
-- share->maps[KSMBD_SHARE_VALID_USERS_MAP] =
-- parse_list(share->maps[KSMBD_SHARE_VALID_USERS_MAP],
-- users_list, '@');
-- if (share->maps[KSMBD_SHARE_VALID_USERS_MAP] == NULL)
-- set_share_flag(share, KSMBD_SHARE_FLAG_INVALID);
-- cp_group_kv_list_free(users_list);
-- return;
-- }
--
-- if (shm_share_config(k, KSMBD_SHARE_CONF_INVALID_USERS)) {
-- char **users_list;
--
-- users_list = cp_get_group_kv_list(v);
-- share->maps[KSMBD_SHARE_INVALID_USERS_MAP] =
-- parse_list(share->maps[KSMBD_SHARE_INVALID_USERS_MAP],
-- users_list, '@');
-- if (share->maps[KSMBD_SHARE_INVALID_USERS_MAP] == NULL)
-- set_share_flag(share, KSMBD_SHARE_FLAG_INVALID);
-- cp_group_kv_list_free(users_list);
-- return;
-- }
--
-- if (shm_share_config(k, KSMBD_SHARE_CONF_READ_LIST)) {
-- char **users_list;
--
-- users_list = cp_get_group_kv_list(v);
-- share->maps[KSMBD_SHARE_READ_LIST_MAP] =
-- parse_list(share->maps[KSMBD_SHARE_READ_LIST_MAP],
-- users_list, '@');
-- if (share->maps[KSMBD_SHARE_READ_LIST_MAP] == NULL)
-- set_share_flag(share, KSMBD_SHARE_FLAG_INVALID);
-- cp_group_kv_list_free(users_list);
-- return;
-- }
--
-- if (shm_share_config(k, KSMBD_SHARE_CONF_WRITE_LIST)) {
-- char **users_list;
--
-- users_list = cp_get_group_kv_list(v);
-- share->maps[KSMBD_SHARE_WRITE_LIST_MAP] =
-- parse_list(share->maps[KSMBD_SHARE_WRITE_LIST_MAP],
-- users_list, '@');
-- if (share->maps[KSMBD_SHARE_WRITE_LIST_MAP] == NULL)
-- set_share_flag(share, KSMBD_SHARE_FLAG_INVALID);
-- cp_group_kv_list_free(users_list);
-- return;
-- }
--
-- if (shm_share_config(k, KSMBD_SHARE_CONF_ADMIN_USERS)) {
-- char **users_list;
--
-- users_list = cp_get_group_kv_list(v);
-- share->maps[KSMBD_SHARE_ADMIN_USERS_MAP] =
-- parse_list(share->maps[KSMBD_SHARE_ADMIN_USERS_MAP],
-- users_list, '@');
-- if (share->maps[KSMBD_SHARE_ADMIN_USERS_MAP] == NULL)
-- set_share_flag(share, KSMBD_SHARE_FLAG_INVALID);
-- cp_group_kv_list_free(users_list);
-- return;
-- }
--
-- if (shm_share_config(k, KSMBD_SHARE_CONF_HOSTS_ALLOW)) {
-- char **hosts_list;
--
-- hosts_list = cp_get_group_kv_list(v);
-- share->hosts_allow_map = parse_list(share->hosts_allow_map,
-- hosts_list, 0x00);
-- if (share->hosts_allow_map == NULL)
-- set_share_flag(share, KSMBD_SHARE_FLAG_INVALID);
-- cp_group_kv_list_free(hosts_list);
-- return;
-- }
--
-- if (shm_share_config(k, KSMBD_SHARE_CONF_HOSTS_DENY)) {
-- char **hosts_list;
--
-- hosts_list = cp_get_group_kv_list(v);
-- share->hosts_deny_map = parse_list(share->hosts_deny_map,
-- hosts_list, 0x00);
-- if (share->hosts_deny_map == NULL)
-- set_share_flag(share, KSMBD_SHARE_FLAG_INVALID);
-- cp_group_kv_list_free(hosts_list);
-- return;
-- }
--
-- if (shm_share_config(k, KSMBD_SHARE_CONF_MAX_CONNECTIONS)) {
-- share->max_connections = cp_get_group_kv_long_base(v, 10);
-- return;
-- }
--
-- if (shm_share_config(k, KSMBD_SHARE_CONF_VETO_FILES)) {
-- share->veto_list = cp_get_group_kv_string(v + 1);
-- if (share->veto_list == NULL) {
-- set_share_flag(share, KSMBD_SHARE_FLAG_INVALID);
-- } else {
-- share->veto_list_sz = strlen(share->veto_list);
-- make_veto_list(share);
-- }
-- return;
-- }
--
-- if (shm_share_config(k, KSMBD_SHARE_CONF_INHERIT_OWNER)) {
-- if (cp_get_group_kv_bool(v))
-- set_share_flag(share, KSMBD_SHARE_FLAG_INHERIT_OWNER);
-- else
-- clear_share_flag(share, KSMBD_SHARE_FLAG_INHERIT_OWNER);
-- }
--
-- if (shm_share_config(k, KSMBD_SHARE_CONF_VFS_OBJECTS)) {
-- char *p;
-- int i;
-- char **objects = cp_get_group_kv_list(v);
--
-- if (objects) {
-- clear_share_flag(share, KSMBD_SHARE_FLAG_ACL_XATTR);
-- clear_share_flag(share, KSMBD_SHARE_FLAG_STREAMS);
-- for (i = 0; objects[i] != NULL; i++) {
-- p = cp_ltrim(objects[i]);
-- if (!p)
-- continue;
-- if (!strcmp(p, "acl_xattr"))
-- set_share_flag(share, KSMBD_SHARE_FLAG_ACL_XATTR);
-- else if (!strcmp(p, "streams_xattr"))
-- set_share_flag(share, KSMBD_SHARE_FLAG_STREAMS);
-- }
-- cp_group_kv_list_free(objects);
-- }
-- }
--
--}
--
--static void fixup_missing_fields(struct ksmbd_share *share)
--{
-- if (!share->comment)
-- share->comment = strdup("");
--}
--
--static void init_share_from_group(struct ksmbd_share *share,
-- struct smbconf_group *group)
--{
-- share->name = g_strdup(group->name);
-- share->create_mask = KSMBD_SHARE_DEFAULT_CREATE_MASK;
-- share->directory_mask = KSMBD_SHARE_DEFAULT_DIRECTORY_MASK;
-- share->force_create_mode = 0;
-- share->force_directory_mode = 0;
--
-- share->force_uid = KSMBD_SHARE_INVALID_UID;
-- share->force_gid = KSMBD_SHARE_INVALID_GID;
--
-- set_share_flag(share, KSMBD_SHARE_FLAG_AVAILABLE);
-- set_share_flag(share, KSMBD_SHARE_FLAG_BROWSEABLE);
-- set_share_flag(share, KSMBD_SHARE_FLAG_READONLY);
-- set_share_flag(share, KSMBD_SHARE_FLAG_HIDE_DOT_FILES);
-- set_share_flag(share, KSMBD_SHARE_FLAG_OPLOCKS);
-- set_share_flag(share, KSMBD_SHARE_FLAG_STORE_DOS_ATTRS);
--
-- if (!g_ascii_strcasecmp(share->name, "ipc$"))
-- set_share_flag(share, KSMBD_SHARE_FLAG_PIPE);
--
-- if (group->cb_mode == GROUPS_CALLBACK_REINIT)
-- set_share_flag(share, KSMBD_SHARE_FLAG_UPDATE);
--
-- g_hash_table_foreach(group->kv, process_group_kv, share);
--
-- fixup_missing_fields(share);
--}
--
--int shm_add_new_share(struct smbconf_group *group)
--{
-- int ret = 0;
-- struct ksmbd_share *share = new_ksmbd_share();
--
-- if (!share)
-- return -ENOMEM;
--
-- init_share_from_group(share, group);
-- if (test_share_flag(share, KSMBD_SHARE_FLAG_INVALID)) {
-- pr_err("Share `%s' is invalid\n", share->name);
-- kill_ksmbd_share(share);
-- return 0;
-- }
--
-- g_rw_lock_writer_lock(&shares_table_lock);
-- if (__shm_lookup_share(share->name)) {
-- g_rw_lock_writer_unlock(&shares_table_lock);
-- pr_info("Share `%s' already exists\n", share->name);
-- kill_ksmbd_share(share);
-- return 0;
-- }
--
-- pr_debug("New share `%s'\n", share->name);
-- if (!g_hash_table_insert(shares_table, share->name, share)) {
-- kill_ksmbd_share(share);
-- ret = -EINVAL;
-- }
-- g_rw_lock_writer_unlock(&shares_table_lock);
-- return ret;
--}
--
--int shm_lookup_users_map(struct ksmbd_share *share,
-- enum share_users map,
-- char *name)
--{
-- int ret = -ENOENT;
--
-- if (map >= KSMBD_SHARE_USERS_MAX) {
-- pr_err("Invalid users map index: %d\n", map);
-- return 0;
-- }
--
-- if (!share->maps[map])
-- return -EINVAL;
--
-- g_rw_lock_reader_lock(&share->maps_lock);
-- if (g_hash_table_lookup(share->maps[map], name))
-- ret = 0;
-- g_rw_lock_reader_unlock(&share->maps_lock);
--
-- return ret;
--}
--
--/*
-- * FIXME
-- * Do a real hosts lookup. IP masks, etc.
-- */
--int shm_lookup_hosts_map(struct ksmbd_share *share,
-- enum share_hosts map,
-- char *host)
--{
-- GHashTable *lookup_map = NULL;
-- int ret = -ENOENT;
--
-- if (map >= KSMBD_SHARE_HOSTS_MAX) {
-- pr_err("Invalid hosts map index: %d\n", map);
-- return 0;
-- }
--
-- if (map == KSMBD_SHARE_HOSTS_ALLOW_MAP)
-- lookup_map = share->hosts_allow_map;
-- if (map == KSMBD_SHARE_HOSTS_DENY_MAP)
-- lookup_map = share->hosts_deny_map;
--
-- if (!lookup_map)
-- return -EINVAL;
--
-- g_rw_lock_reader_lock(&share->maps_lock);
-- if (g_hash_table_lookup(lookup_map, host))
-- ret = 0;
-- g_rw_lock_reader_unlock(&share->maps_lock);
--
-- return ret;
--}
--
--int shm_open_connection(struct ksmbd_share *share)
--{
-- int ret = 0;
--
-- g_rw_lock_writer_lock(&share->update_lock);
-- share->num_connections++;
-- if (share->max_connections) {
-- if (share->num_connections >= share->max_connections)
-- ret = -EINVAL;
-- }
-- g_rw_lock_writer_unlock(&share->update_lock);
-- return ret;
--}
--
--int shm_close_connection(struct ksmbd_share *share)
--{
-- if (!share)
-- return 0;
--
-- g_rw_lock_writer_lock(&share->update_lock);
-- share->num_connections--;
-- g_rw_lock_writer_unlock(&share->update_lock);
-- return 0;
--}
--
--void for_each_ksmbd_share(walk_shares cb, gpointer user_data)
--{
-- g_rw_lock_reader_lock(&shares_table_lock);
-- g_hash_table_foreach(shares_table, cb, user_data);
-- g_rw_lock_reader_unlock(&shares_table_lock);
--}
--
--int shm_share_config_payload_size(struct ksmbd_share *share)
--{
-- int sz = 1;
--
-- if (share && !test_share_flag(share, KSMBD_SHARE_FLAG_PIPE)) {
-- if (share->path)
-- sz += strlen(share->path);
-- if (global_conf.root_dir)
-- sz += strlen(global_conf.root_dir) + 1;
-- if (share->veto_list_sz)
-- sz += share->veto_list_sz + 1;
-- }
--
-- return sz;
--}
--
--int shm_handle_share_config_request(struct ksmbd_share *share,
-- struct ksmbd_share_config_response *resp)
--{
-- unsigned char *config_payload;
--
-- if (!share)
-- return -EINVAL;
--
-- resp->flags = share->flags;
-- resp->create_mask = share->create_mask;
-- resp->directory_mask = share->directory_mask;
-- resp->force_create_mode = share->force_create_mode;
-- resp->force_directory_mode = share->force_directory_mode;
-- resp->force_uid = share->force_uid;
-- resp->force_gid = share->force_gid;
-- *resp->share_name = 0x00;
-- strncat(resp->share_name, share->name, KSMBD_REQ_MAX_SHARE_NAME - 1);
-- resp->veto_list_sz = share->veto_list_sz;
--
-- if (test_share_flag(share, KSMBD_SHARE_FLAG_PIPE))
-- return 0;
--
-- if (!share->path)
-- return 0;
--
-- config_payload = KSMBD_SHARE_CONFIG_VETO_LIST(resp);
-- if (resp->veto_list_sz) {
-- memcpy(config_payload,
-- share->veto_list,
-- resp->veto_list_sz);
-- config_payload += resp->veto_list_sz + 1;
-- }
-- if (global_conf.root_dir)
-- sprintf(config_payload,
-- "%s%s",
-- global_conf.root_dir,
-- share->path);
-- else
-- sprintf(config_payload, "%s", share->path);
-- return 0;
--}
---- /dev/null
-+++ b/tools/management/share.c
-@@ -0,0 +1,868 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+/*
-+ * Copyright (C) 2018 Samsung Electronics Co., Ltd.
-+ *
-+ * linux-cifsd-devel@lists.sourceforge.net
-+ */
-+
-+#include <stdlib.h>
-+#include <string.h>
-+#include <glib.h>
-+#include <sys/types.h>
-+#include <pwd.h>
-+#include <grp.h>
-+
-+#include "config_parser.h"
-+#include "linux/ksmbd_server.h"
-+#include "management/share.h"
-+#include "management/user.h"
-+#include "tools.h"
-+
-+#define KSMBD_SHARE_STATE_FREEING 1
-+
-+/*
-+ * WARNING:
-+ *
-+ * This must match KSMBD_SHARE_CONF enum 1:1.
-+ * Add new entries ONLY to the bottom.
-+ */
-+char *KSMBD_SHARE_CONF[KSMBD_SHARE_CONF_MAX] = {
-+ "comment", /* 0 */
-+ "path",
-+ "guest ok",
-+ "guest account",
-+ "read only",
-+ "browseable", /* 5 */
-+ "write ok",
-+ "writeable",
-+ "store dos attributes",
-+ "oplocks",
-+ "create mask", /* 10 */
-+ "directory mask",
-+ "force create mode",
-+ "force directory mode",
-+ "force group",
-+ "force user", /* 15 */
-+ "hide dot files",
-+ "valid users",
-+ "invalid users",
-+ "read list",
-+ "write list", /* 20 */
-+ "admin users",
-+ "hosts allow",
-+ "hosts deny",
-+ "max connections",
-+ "veto files", /* 25 */
-+ "inherit owner",
-+ "follow symlinks",
-+ "vfs objects",
-+ "writable",
-+};
-+
-+static GHashTable *shares_table;
-+static GRWLock shares_table_lock;
-+
-+int shm_share_config(char *k, enum KSMBD_SHARE_CONF c)
-+{
-+ if (c >= KSMBD_SHARE_CONF_MAX)
-+ return 0;
-+
-+ return !cp_key_cmp(k, KSMBD_SHARE_CONF[c]);
-+}
-+
-+static void list_hosts_callback(gpointer k, gpointer v, gpointer user_data)
-+{
-+ free(k);
-+ free(v);
-+}
-+
-+static void free_hosts_map(GHashTable *map)
-+{
-+ if (map) {
-+ g_hash_table_foreach(map, list_hosts_callback, NULL);
-+ g_hash_table_destroy(map);
-+ }
-+}
-+
-+static void list_user_callback(gpointer k, gpointer u, gpointer user_data)
-+{
-+ put_ksmbd_user((struct ksmbd_user *)u);
-+}
-+
-+static void free_user_map(GHashTable *map)
-+{
-+ if (map) {
-+ g_hash_table_foreach(map, list_user_callback, NULL);
-+ g_hash_table_destroy(map);
-+ }
-+}
-+
-+static void kill_ksmbd_share(struct ksmbd_share *share)
-+{
-+ int i;
-+
-+ pr_debug("Kill share `%s'\n", share->name);
-+
-+ for (i = 0; i < KSMBD_SHARE_USERS_MAX; i++)
-+ free_user_map(share->maps[i]);
-+
-+ free_hosts_map(share->hosts_allow_map);
-+ free_hosts_map(share->hosts_deny_map);
-+
-+ g_rw_lock_clear(&share->maps_lock);
-+
-+ free(share->name);
-+ free(share->path);
-+ free(share->comment);
-+ free(share->veto_list);
-+ free(share->guest_account);
-+ g_rw_lock_clear(&share->update_lock);
-+ g_free(share);
-+}
-+
-+static int __shm_remove_share(struct ksmbd_share *share)
-+{
-+ int ret = 0;
-+
-+ if (share->state != KSMBD_SHARE_STATE_FREEING) {
-+ g_rw_lock_writer_lock(&shares_table_lock);
-+ if (!g_hash_table_remove(shares_table, share->name))
-+ ret = -EINVAL;
-+ g_rw_lock_writer_unlock(&shares_table_lock);
-+ }
-+ if (!ret)
-+ kill_ksmbd_share(share);
-+ return ret;
-+}
-+
-+struct ksmbd_share *get_ksmbd_share(struct ksmbd_share *share)
-+{
-+ g_rw_lock_writer_lock(&share->update_lock);
-+ if (share->ref_count != 0) {
-+ share->ref_count++;
-+ g_rw_lock_writer_unlock(&share->update_lock);
-+ } else {
-+ g_rw_lock_writer_unlock(&share->update_lock);
-+ share = NULL;
-+ }
-+
-+ return share;
-+}
-+
-+void put_ksmbd_share(struct ksmbd_share *share)
-+{
-+ int drop;
-+
-+ if (!share)
-+ return;
-+
-+ g_rw_lock_writer_lock(&share->update_lock);
-+ share->ref_count--;
-+ drop = !share->ref_count;
-+ g_rw_lock_writer_unlock(&share->update_lock);
-+
-+ if (!drop)
-+ return;
-+
-+ __shm_remove_share(share);
-+}
-+
-+static gboolean put_share_callback(gpointer _k, gpointer _v, gpointer data)
-+{
-+ struct ksmbd_share *share = (struct ksmbd_share *)_v;
-+
-+ share->state = KSMBD_SHARE_STATE_FREEING;
-+ put_ksmbd_share(share);
-+ return TRUE;
-+}
-+
-+void shm_remove_all_shares(void)
-+{
-+ g_rw_lock_writer_lock(&shares_table_lock);
-+ g_hash_table_foreach_remove(shares_table, put_share_callback, NULL);
-+ g_rw_lock_writer_unlock(&shares_table_lock);
-+}
-+
-+static struct ksmbd_share *new_ksmbd_share(void)
-+{
-+ struct ksmbd_share *share;
-+ int i;
-+
-+ share = g_try_malloc0(sizeof(struct ksmbd_share));
-+ if (!share)
-+ return NULL;
-+
-+ share->ref_count = 1;
-+ /*
-+ * Create maps as needed. NULL maps means that share
-+ * does not have a corresponding shmbconf entry.
-+ */
-+ for (i = 0; i < KSMBD_SHARE_USERS_MAX; i++)
-+ share->maps[i] = NULL;
-+
-+ share->hosts_allow_map = NULL;
-+ share->hosts_deny_map = NULL;
-+ g_rw_lock_init(&share->maps_lock);
-+ g_rw_lock_init(&share->update_lock);
-+
-+ return share;
-+}
-+
-+static void free_hash_entry(gpointer k, gpointer s, gpointer user_data)
-+{
-+ kill_ksmbd_share(s);
-+}
-+
-+static void shm_clear_shares(void)
-+{
-+ g_hash_table_foreach(shares_table, free_hash_entry, NULL);
-+}
-+
-+void shm_destroy(void)
-+{
-+ if (shares_table) {
-+ shm_clear_shares();
-+ g_hash_table_destroy(shares_table);
-+ }
-+ g_rw_lock_clear(&shares_table_lock);
-+}
-+
-+static char *shm_casefold_share_name(const char *name, size_t len)
-+{
-+ char *nfdi_name, *nfdicf_name;
-+
-+ nfdi_name = g_utf8_normalize(name, len, G_NORMALIZE_NFD);
-+ if (!nfdi_name)
-+ goto out_ascii;
-+
-+ nfdicf_name = g_utf8_casefold(nfdi_name, strlen(nfdi_name));
-+ g_free(nfdi_name);
-+ return nfdicf_name;
-+out_ascii:
-+ g_free(nfdi_name);
-+ return g_ascii_strdown(name, len);
-+}
-+
-+guint shm_share_name_hash(gconstpointer name)
-+{
-+ char *cf_name;
-+ guint hash;
-+
-+ cf_name = shm_casefold_share_name(name, strlen(name));
-+ hash = g_str_hash(cf_name);
-+ g_free(cf_name);
-+ return hash;
-+}
-+
-+gboolean shm_share_name_equal(gconstpointer lname, gconstpointer rname)
-+{
-+ char *cf_lname, *cf_rname;
-+ gboolean equal;
-+
-+ cf_lname = shm_casefold_share_name(lname, strlen(lname));
-+ cf_rname = shm_casefold_share_name(rname, strlen(rname));
-+ equal = g_str_equal(cf_lname, cf_rname);
-+ g_free(cf_lname);
-+ g_free(cf_rname);
-+ return equal;
-+}
-+
-+int shm_init(void)
-+{
-+ shares_table = g_hash_table_new(shm_share_name_hash,
-+ shm_share_name_equal);
-+ if (!shares_table)
-+ return -ENOMEM;
-+ g_rw_lock_init(&shares_table_lock);
-+ return 0;
-+}
-+
-+static struct ksmbd_share *__shm_lookup_share(char *name)
-+{
-+ return g_hash_table_lookup(shares_table, name);
-+}
-+
-+struct ksmbd_share *shm_lookup_share(char *name)
-+{
-+ struct ksmbd_share *share, *ret;
-+
-+ g_rw_lock_reader_lock(&shares_table_lock);
-+ share = __shm_lookup_share(name);
-+ if (share) {
-+ ret = get_ksmbd_share(share);
-+ if (!ret)
-+ share = NULL;
-+ }
-+ g_rw_lock_reader_unlock(&shares_table_lock);
-+ return share;
-+}
-+
-+static GHashTable *parse_list(GHashTable *map, char **list, char grc)
-+{
-+ int i;
-+
-+ if (!list)
-+ return map;
-+
-+ if (!map)
-+ map = g_hash_table_new(g_str_hash, g_str_equal);
-+ if (!map)
-+ return map;
-+
-+ for (i = 0; list[i] != NULL; i++) {
-+ struct ksmbd_user *user;
-+ char *p = list[i];
-+
-+ p = cp_ltrim(p);
-+ if (!p)
-+ continue;
-+
-+ if (*p == grc) {
-+ struct group *gr;
-+
-+ gr = getgrnam(p + 1);
-+ if (gr)
-+ parse_list(map, gr->gr_mem, 0x00);
-+ continue;
-+ }
-+
-+ user = usm_lookup_user(p);
-+ if (!user) {
-+ pr_info("Drop non-existing user `%s'\n", p);
-+ continue;
-+ }
-+
-+ if (g_hash_table_lookup(map, user->name)) {
-+ pr_debug("User `%s' already exists in a map\n",
-+ user->name);
-+ continue;
-+ }
-+
-+ g_hash_table_insert(map, user->name, user);
-+ }
-+
-+ return map;
-+}
-+
-+static void make_veto_list(struct ksmbd_share *share)
-+{
-+ int i;
-+
-+ for (i = 0; i < share->veto_list_sz; i++) {
-+ if (share->veto_list[i] == '/')
-+ share->veto_list[i] = 0x00;
-+ }
-+}
-+
-+static void force_group(struct ksmbd_share *share, char *name)
-+{
-+ struct group *grp;
-+
-+ grp = getgrnam(name);
-+ if (grp) {
-+ share->force_gid = grp->gr_gid;
-+ if (share->force_gid == KSMBD_SHARE_INVALID_GID)
-+ pr_err("Invalid force GID: %u\n", share->force_gid);
-+ } else
-+ pr_err("Unable to lookup up `/etc/group' entry: %s\n", name);
-+}
-+
-+static void force_user(struct ksmbd_share *share, char *name)
-+{
-+ struct passwd *passwd;
-+
-+ passwd = getpwnam(name);
-+ if (passwd) {
-+ share->force_uid = passwd->pw_uid;
-+ /*
-+ * smb.conf 'force group' has higher priority than
-+ * 'force user'.
-+ */
-+ if (share->force_gid == KSMBD_SHARE_INVALID_GID)
-+ share->force_gid = passwd->pw_gid;
-+ if (share->force_uid == KSMBD_SHARE_INVALID_UID ||
-+ share->force_gid == KSMBD_SHARE_INVALID_GID)
-+ pr_err("Invalid force UID/GID: %u/%u\n",
-+ share->force_uid, share->force_gid);
-+ } else {
-+ pr_err("Unable to lookup up `/etc/passwd' entry: %s\n", name);
-+ }
-+}
-+
-+static void process_group_kv(gpointer _k, gpointer _v, gpointer user_data)
-+{
-+ struct ksmbd_share *share = user_data;
-+ char *k = _k;
-+ char *v = _v;
-+
-+ if (shm_share_config(k, KSMBD_SHARE_CONF_COMMENT)) {
-+ share->comment = cp_get_group_kv_string(v);
-+ if (share->comment == NULL)
-+ set_share_flag(share, KSMBD_SHARE_FLAG_INVALID);
-+ return;
-+ }
-+
-+ if (shm_share_config(k, KSMBD_SHARE_CONF_PATH)) {
-+ share->path = cp_get_group_kv_string(v);
-+ if (share->path == NULL)
-+ set_share_flag(share, KSMBD_SHARE_FLAG_INVALID);
-+ return;
-+ }
-+
-+ if (shm_share_config(k, KSMBD_SHARE_CONF_GUEST_OK)) {
-+ if (cp_get_group_kv_bool(v))
-+ set_share_flag(share, KSMBD_SHARE_FLAG_GUEST_OK);
-+ return;
-+ }
-+
-+ if (shm_share_config(k, KSMBD_SHARE_CONF_GUEST_ACCOUNT)) {
-+ struct ksmbd_user *user;
-+
-+ if (usm_add_new_user(cp_get_group_kv_string(_v),
-+ g_strdup("NULL"))) {
-+ pr_err("Unable to add guest account\n");
-+ set_share_flag(share, KSMBD_SHARE_FLAG_INVALID);
-+ return;
-+ }
-+
-+ user = usm_lookup_user(_v);
-+ if (user) {
-+ set_user_flag(user, KSMBD_USER_FLAG_GUEST_ACCOUNT);
-+ put_ksmbd_user(user);
-+ }
-+ share->guest_account = cp_get_group_kv_string(_v);
-+ if (!share->guest_account)
-+ set_share_flag(share, KSMBD_SHARE_FLAG_INVALID);
-+ return;
-+ }
-+
-+ if (shm_share_config(k, KSMBD_SHARE_CONF_READ_ONLY)) {
-+ if (cp_get_group_kv_bool(v)) {
-+ set_share_flag(share, KSMBD_SHARE_FLAG_READONLY);
-+ clear_share_flag(share, KSMBD_SHARE_FLAG_WRITEABLE);
-+ } else {
-+ clear_share_flag(share, KSMBD_SHARE_FLAG_READONLY);
-+ set_share_flag(share, KSMBD_SHARE_FLAG_WRITEABLE);
-+ }
-+ return;
-+ }
-+
-+ if (shm_share_config(k, KSMBD_SHARE_CONF_BROWSEABLE)) {
-+ if (cp_get_group_kv_bool(v))
-+ set_share_flag(share, KSMBD_SHARE_FLAG_BROWSEABLE);
-+ else
-+ clear_share_flag(share, KSMBD_SHARE_FLAG_BROWSEABLE);
-+ return;
-+ }
-+
-+ if (shm_share_config(k, KSMBD_SHARE_CONF_WRITE_OK) ||
-+ shm_share_config(k, KSMBD_SHARE_CONF_WRITEABLE) ||
-+ shm_share_config(k, KSMBD_SHARE_CONF_WRITABLE)) {
-+ if (cp_get_group_kv_bool(v))
-+ set_share_flag(share, KSMBD_SHARE_FLAG_WRITEABLE);
-+ else
-+ clear_share_flag(share, KSMBD_SHARE_FLAG_WRITEABLE);
-+ return;
-+ }
-+
-+ if (shm_share_config(k, KSMBD_SHARE_CONF_STORE_DOS_ATTRIBUTES)) {
-+ if (cp_get_group_kv_bool(v))
-+ set_share_flag(share, KSMBD_SHARE_FLAG_STORE_DOS_ATTRS);
-+ else
-+ clear_share_flag(share,
-+ KSMBD_SHARE_FLAG_STORE_DOS_ATTRS);
-+ return;
-+ }
-+
-+ if (shm_share_config(k, KSMBD_SHARE_CONF_OPLOCKS)) {
-+ if (cp_get_group_kv_bool(v))
-+ set_share_flag(share, KSMBD_SHARE_FLAG_OPLOCKS);
-+ else
-+ clear_share_flag(share, KSMBD_SHARE_FLAG_OPLOCKS);
-+ return;
-+ }
-+
-+ if (shm_share_config(k, KSMBD_SHARE_CONF_CREATE_MASK)) {
-+ share->create_mask = cp_get_group_kv_long_base(v, 8);
-+ return;
-+ }
-+
-+ if (shm_share_config(k, KSMBD_SHARE_CONF_DIRECTORY_MASK)) {
-+ share->directory_mask = cp_get_group_kv_long_base(v, 8);
-+ return;
-+ }
-+
-+ if (shm_share_config(k, KSMBD_SHARE_CONF_FORCE_CREATE_MODE)) {
-+ share->force_create_mode = cp_get_group_kv_long_base(v, 8);
-+ return;
-+ }
-+
-+ if (shm_share_config(k, KSMBD_SHARE_CONF_FORCE_DIRECTORY_MODE)) {
-+ share->force_directory_mode = cp_get_group_kv_long_base(v, 8);
-+ return;
-+ }
-+
-+ if (shm_share_config(k, KSMBD_SHARE_CONF_FORCE_GROUP)) {
-+ force_group(share, v);
-+ return;
-+ }
-+
-+ if (shm_share_config(k, KSMBD_SHARE_CONF_FORCE_USER)) {
-+ force_user(share, v);
-+ return;
-+ }
-+
-+ if (shm_share_config(k, KSMBD_SHARE_CONF_HIDE_DOT_FILES)) {
-+ if (cp_get_group_kv_bool(v))
-+ set_share_flag(share, KSMBD_SHARE_FLAG_HIDE_DOT_FILES);
-+ else
-+ clear_share_flag(share,
-+ KSMBD_SHARE_FLAG_HIDE_DOT_FILES);
-+ }
-+
-+ if (shm_share_config(k, KSMBD_SHARE_CONF_VALID_USERS)) {
-+ char **users_list;
-+
-+ users_list = cp_get_group_kv_list(v);
-+ share->maps[KSMBD_SHARE_VALID_USERS_MAP] =
-+ parse_list(share->maps[KSMBD_SHARE_VALID_USERS_MAP],
-+ users_list, '@');
-+ if (share->maps[KSMBD_SHARE_VALID_USERS_MAP] == NULL)
-+ set_share_flag(share, KSMBD_SHARE_FLAG_INVALID);
-+ cp_group_kv_list_free(users_list);
-+ return;
-+ }
-+
-+ if (shm_share_config(k, KSMBD_SHARE_CONF_INVALID_USERS)) {
-+ char **users_list;
-+
-+ users_list = cp_get_group_kv_list(v);
-+ share->maps[KSMBD_SHARE_INVALID_USERS_MAP] =
-+ parse_list(share->maps[KSMBD_SHARE_INVALID_USERS_MAP],
-+ users_list, '@');
-+ if (share->maps[KSMBD_SHARE_INVALID_USERS_MAP] == NULL)
-+ set_share_flag(share, KSMBD_SHARE_FLAG_INVALID);
-+ cp_group_kv_list_free(users_list);
-+ return;
-+ }
-+
-+ if (shm_share_config(k, KSMBD_SHARE_CONF_READ_LIST)) {
-+ char **users_list;
-+
-+ users_list = cp_get_group_kv_list(v);
-+ share->maps[KSMBD_SHARE_READ_LIST_MAP] =
-+ parse_list(share->maps[KSMBD_SHARE_READ_LIST_MAP],
-+ users_list, '@');
-+ if (share->maps[KSMBD_SHARE_READ_LIST_MAP] == NULL)
-+ set_share_flag(share, KSMBD_SHARE_FLAG_INVALID);
-+ cp_group_kv_list_free(users_list);
-+ return;
-+ }
-+
-+ if (shm_share_config(k, KSMBD_SHARE_CONF_WRITE_LIST)) {
-+ char **users_list;
-+
-+ users_list = cp_get_group_kv_list(v);
-+ share->maps[KSMBD_SHARE_WRITE_LIST_MAP] =
-+ parse_list(share->maps[KSMBD_SHARE_WRITE_LIST_MAP],
-+ users_list, '@');
-+ if (share->maps[KSMBD_SHARE_WRITE_LIST_MAP] == NULL)
-+ set_share_flag(share, KSMBD_SHARE_FLAG_INVALID);
-+ cp_group_kv_list_free(users_list);
-+ return;
-+ }
-+
-+ if (shm_share_config(k, KSMBD_SHARE_CONF_ADMIN_USERS)) {
-+ char **users_list;
-+
-+ users_list = cp_get_group_kv_list(v);
-+ share->maps[KSMBD_SHARE_ADMIN_USERS_MAP] =
-+ parse_list(share->maps[KSMBD_SHARE_ADMIN_USERS_MAP],
-+ users_list, '@');
-+ if (share->maps[KSMBD_SHARE_ADMIN_USERS_MAP] == NULL)
-+ set_share_flag(share, KSMBD_SHARE_FLAG_INVALID);
-+ cp_group_kv_list_free(users_list);
-+ return;
-+ }
-+
-+ if (shm_share_config(k, KSMBD_SHARE_CONF_HOSTS_ALLOW)) {
-+ char **hosts_list;
-+
-+ hosts_list = cp_get_group_kv_list(v);
-+ share->hosts_allow_map = parse_list(share->hosts_allow_map,
-+ hosts_list, 0x00);
-+ if (share->hosts_allow_map == NULL)
-+ set_share_flag(share, KSMBD_SHARE_FLAG_INVALID);
-+ cp_group_kv_list_free(hosts_list);
-+ return;
-+ }
-+
-+ if (shm_share_config(k, KSMBD_SHARE_CONF_HOSTS_DENY)) {
-+ char **hosts_list;
-+
-+ hosts_list = cp_get_group_kv_list(v);
-+ share->hosts_deny_map = parse_list(share->hosts_deny_map,
-+ hosts_list, 0x00);
-+ if (share->hosts_deny_map == NULL)
-+ set_share_flag(share, KSMBD_SHARE_FLAG_INVALID);
-+ cp_group_kv_list_free(hosts_list);
-+ return;
-+ }
-+
-+ if (shm_share_config(k, KSMBD_SHARE_CONF_MAX_CONNECTIONS)) {
-+ share->max_connections = cp_get_group_kv_long_base(v, 10);
-+ return;
-+ }
-+
-+ if (shm_share_config(k, KSMBD_SHARE_CONF_VETO_FILES)) {
-+ share->veto_list = cp_get_group_kv_string(v + 1);
-+ if (share->veto_list == NULL) {
-+ set_share_flag(share, KSMBD_SHARE_FLAG_INVALID);
-+ } else {
-+ share->veto_list_sz = strlen(share->veto_list);
-+ make_veto_list(share);
-+ }
-+ return;
-+ }
-+
-+ if (shm_share_config(k, KSMBD_SHARE_CONF_INHERIT_OWNER)) {
-+ if (cp_get_group_kv_bool(v))
-+ set_share_flag(share, KSMBD_SHARE_FLAG_INHERIT_OWNER);
-+ else
-+ clear_share_flag(share, KSMBD_SHARE_FLAG_INHERIT_OWNER);
-+ }
-+
-+ if (shm_share_config(k, KSMBD_SHARE_CONF_VFS_OBJECTS)) {
-+ char *p;
-+ int i;
-+ char **objects = cp_get_group_kv_list(v);
-+
-+ if (objects) {
-+ clear_share_flag(share, KSMBD_SHARE_FLAG_ACL_XATTR);
-+ clear_share_flag(share, KSMBD_SHARE_FLAG_STREAMS);
-+ for (i = 0; objects[i] != NULL; i++) {
-+ p = cp_ltrim(objects[i]);
-+ if (!p)
-+ continue;
-+ if (!strcmp(p, "acl_xattr"))
-+ set_share_flag(share, KSMBD_SHARE_FLAG_ACL_XATTR);
-+ else if (!strcmp(p, "streams_xattr"))
-+ set_share_flag(share, KSMBD_SHARE_FLAG_STREAMS);
-+ }
-+ cp_group_kv_list_free(objects);
-+ }
-+ }
-+
-+}
-+
-+static void fixup_missing_fields(struct ksmbd_share *share)
-+{
-+ if (!share->comment)
-+ share->comment = strdup("");
-+}
-+
-+static void init_share_from_group(struct ksmbd_share *share,
-+ struct smbconf_group *group)
-+{
-+ share->name = g_strdup(group->name);
-+ share->create_mask = KSMBD_SHARE_DEFAULT_CREATE_MASK;
-+ share->directory_mask = KSMBD_SHARE_DEFAULT_DIRECTORY_MASK;
-+ share->force_create_mode = 0;
-+ share->force_directory_mode = 0;
-+
-+ share->force_uid = KSMBD_SHARE_INVALID_UID;
-+ share->force_gid = KSMBD_SHARE_INVALID_GID;
-+
-+ set_share_flag(share, KSMBD_SHARE_FLAG_AVAILABLE);
-+ set_share_flag(share, KSMBD_SHARE_FLAG_BROWSEABLE);
-+ set_share_flag(share, KSMBD_SHARE_FLAG_READONLY);
-+ set_share_flag(share, KSMBD_SHARE_FLAG_HIDE_DOT_FILES);
-+ set_share_flag(share, KSMBD_SHARE_FLAG_OPLOCKS);
-+ set_share_flag(share, KSMBD_SHARE_FLAG_STORE_DOS_ATTRS);
-+
-+ if (!g_ascii_strcasecmp(share->name, "ipc$"))
-+ set_share_flag(share, KSMBD_SHARE_FLAG_PIPE);
-+
-+ if (group->cb_mode == GROUPS_CALLBACK_REINIT)
-+ set_share_flag(share, KSMBD_SHARE_FLAG_UPDATE);
-+
-+ g_hash_table_foreach(group->kv, process_group_kv, share);
-+
-+ fixup_missing_fields(share);
-+}
-+
-+int shm_add_new_share(struct smbconf_group *group)
-+{
-+ int ret = 0;
-+ struct ksmbd_share *share = new_ksmbd_share();
-+
-+ if (!share)
-+ return -ENOMEM;
-+
-+ init_share_from_group(share, group);
-+ if (test_share_flag(share, KSMBD_SHARE_FLAG_INVALID)) {
-+ pr_err("Share `%s' is invalid\n", share->name);
-+ kill_ksmbd_share(share);
-+ return 0;
-+ }
-+
-+ g_rw_lock_writer_lock(&shares_table_lock);
-+ if (__shm_lookup_share(share->name)) {
-+ g_rw_lock_writer_unlock(&shares_table_lock);
-+ pr_info("Share `%s' already exists\n", share->name);
-+ kill_ksmbd_share(share);
-+ return 0;
-+ }
-+
-+ pr_debug("New share `%s'\n", share->name);
-+ if (!g_hash_table_insert(shares_table, share->name, share)) {
-+ kill_ksmbd_share(share);
-+ ret = -EINVAL;
-+ }
-+ g_rw_lock_writer_unlock(&shares_table_lock);
-+ return ret;
-+}
-+
-+int shm_lookup_users_map(struct ksmbd_share *share,
-+ enum share_users map,
-+ char *name)
-+{
-+ int ret = -ENOENT;
-+
-+ if (map >= KSMBD_SHARE_USERS_MAX) {
-+ pr_err("Invalid users map index: %d\n", map);
-+ return 0;
-+ }
-+
-+ if (!share->maps[map])
-+ return -EINVAL;
-+
-+ g_rw_lock_reader_lock(&share->maps_lock);
-+ if (g_hash_table_lookup(share->maps[map], name))
-+ ret = 0;
-+ g_rw_lock_reader_unlock(&share->maps_lock);
-+
-+ return ret;
-+}
-+
-+/*
-+ * FIXME
-+ * Do a real hosts lookup. IP masks, etc.
-+ */
-+int shm_lookup_hosts_map(struct ksmbd_share *share,
-+ enum share_hosts map,
-+ char *host)
-+{
-+ GHashTable *lookup_map = NULL;
-+ int ret = -ENOENT;
-+
-+ if (map >= KSMBD_SHARE_HOSTS_MAX) {
-+ pr_err("Invalid hosts map index: %d\n", map);
-+ return 0;
-+ }
-+
-+ if (map == KSMBD_SHARE_HOSTS_ALLOW_MAP)
-+ lookup_map = share->hosts_allow_map;
-+ if (map == KSMBD_SHARE_HOSTS_DENY_MAP)
-+ lookup_map = share->hosts_deny_map;
-+
-+ if (!lookup_map)
-+ return -EINVAL;
-+
-+ g_rw_lock_reader_lock(&share->maps_lock);
-+ if (g_hash_table_lookup(lookup_map, host))
-+ ret = 0;
-+ g_rw_lock_reader_unlock(&share->maps_lock);
-+
-+ return ret;
-+}
-+
-+int shm_open_connection(struct ksmbd_share *share)
-+{
-+ int ret = 0;
-+
-+ g_rw_lock_writer_lock(&share->update_lock);
-+ share->num_connections++;
-+ if (share->max_connections) {
-+ if (share->num_connections >= share->max_connections)
-+ ret = -EINVAL;
-+ }
-+ g_rw_lock_writer_unlock(&share->update_lock);
-+ return ret;
-+}
-+
-+int shm_close_connection(struct ksmbd_share *share)
-+{
-+ if (!share)
-+ return 0;
-+
-+ g_rw_lock_writer_lock(&share->update_lock);
-+ share->num_connections--;
-+ g_rw_lock_writer_unlock(&share->update_lock);
-+ return 0;
-+}
-+
-+void for_each_ksmbd_share(walk_shares cb, gpointer user_data)
-+{
-+ g_rw_lock_reader_lock(&shares_table_lock);
-+ g_hash_table_foreach(shares_table, cb, user_data);
-+ g_rw_lock_reader_unlock(&shares_table_lock);
-+}
-+
-+int shm_share_config_payload_size(struct ksmbd_share *share)
-+{
-+ int sz = 1;
-+
-+ if (share && !test_share_flag(share, KSMBD_SHARE_FLAG_PIPE)) {
-+ if (share->path)
-+ sz += strlen(share->path);
-+ if (global_conf.root_dir)
-+ sz += strlen(global_conf.root_dir) + 1;
-+ if (share->veto_list_sz)
-+ sz += share->veto_list_sz + 1;
-+ }
-+
-+ return sz;
-+}
-+
-+int shm_handle_share_config_request(struct ksmbd_share *share,
-+ struct ksmbd_share_config_response *resp)
-+{
-+ unsigned char *config_payload;
-+
-+ if (!share)
-+ return -EINVAL;
-+
-+ resp->flags = share->flags;
-+ resp->create_mask = share->create_mask;
-+ resp->directory_mask = share->directory_mask;
-+ resp->force_create_mode = share->force_create_mode;
-+ resp->force_directory_mode = share->force_directory_mode;
-+ resp->force_uid = share->force_uid;
-+ resp->force_gid = share->force_gid;
-+ *resp->share_name = 0x00;
-+ strncat(resp->share_name, share->name, KSMBD_REQ_MAX_SHARE_NAME - 1);
-+ resp->veto_list_sz = share->veto_list_sz;
-+
-+ if (test_share_flag(share, KSMBD_SHARE_FLAG_PIPE))
-+ return 0;
-+
-+ if (!share->path)
-+ return 0;
-+
-+ config_payload = KSMBD_SHARE_CONFIG_VETO_LIST(resp);
-+ if (resp->veto_list_sz) {
-+ memcpy(config_payload,
-+ share->veto_list,
-+ resp->veto_list_sz);
-+ config_payload += resp->veto_list_sz + 1;
-+ }
-+ if (global_conf.root_dir)
-+ sprintf(config_payload,
-+ "%s%s",
-+ global_conf.root_dir,
-+ share->path);
-+ else
-+ sprintf(config_payload, "%s", share->path);
-+ return 0;
-+}
---- a/lib/management/spnego.c
-+++ /dev/null
-@@ -1,348 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0-or-later
--/*
-- * Copyright (C) 2020 LG Electronics
-- *
-- * linux-cifsd-devel@lists.sourceforge.net
-- */
--
--#include "ksmbdtools.h"
--
--#ifndef _GNU_SOURCE
--#define _GNU_SOURCE
--#endif
--
--#include <stdlib.h>
--#include <stdio.h>
--#include <unistd.h>
--#include <sys/types.h>
--#include <fcntl.h>
--#include <stdint.h>
--#include <stdbool.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];
--
--static struct spnego_mech_ctx *get_mech(int mech_type)
--{
-- if (mech_type >= SPNEGO_MAX_MECHS)
-- return NULL;
-- return &mech_ctxs[mech_type];
--}
--
--int spnego_init(void)
--{
-- struct spnego_mech_ctx *mech_ctx;
-- int i;
--
-- mech_ctx = &mech_ctxs[SPNEGO_MECH_MSKRB5];
-- mech_ctx->ops = &spnego_mskrb5_operations;
-- if (global_conf.krb5_service_name)
-- mech_ctx->params.krb5.service_name =
-- strdup(global_conf.krb5_service_name);
-- if (global_conf.krb5_keytab_file)
-- mech_ctx->params.krb5.keytab_name =
-- strdup(global_conf.krb5_keytab_file);
--
-- mech_ctx = &mech_ctxs[SPNEGO_MECH_KRB5];
-- mech_ctx->ops = &spnego_krb5_operations;
-- if (global_conf.krb5_service_name)
-- mech_ctx->params.krb5.service_name =
-- strdup(global_conf.krb5_service_name);
-- if (global_conf.krb5_keytab_file)
-- mech_ctx->params.krb5.keytab_name =
-- strdup(global_conf.krb5_keytab_file);
--
-- for (i = 0; i < SPNEGO_MAX_MECHS; i++) {
-- if (mech_ctxs[i].ops->setup &&
-- mech_ctxs[i].ops->setup(&mech_ctxs[i])) {
-- pr_err("Failed to init Kerberos 5\n");
-- goto out_err;
-- }
-- }
--
-- return 0;
--out_err:
-- for (; i >= 0; i--) {
-- if (mech_ctxs[i].ops->cleanup)
-- mech_ctxs[i].ops->cleanup(&mech_ctxs[i]);
-- }
-- return -ENOTSUP;
--}
--
--void spnego_destroy(void)
--{
-- int i;
--
-- for (i = 0; i < SPNEGO_MAX_MECHS; i++) {
-- if (mech_ctxs[i].ops && mech_ctxs[i].ops->cleanup)
-- mech_ctxs[i].ops->cleanup(&mech_ctxs[i]);
-- }
--}
--
--static int compare_oid(unsigned long *oid1, unsigned int oid1len,
-- unsigned long *oid2, unsigned int oid2len)
--{
-- unsigned int i;
--
-- if (oid1len != oid2len)
-- return 1;
--
-- for (i = 0; i < oid1len; i++) {
-- if (oid1[i] != oid2[i])
-- return 1;
-- }
-- return 0;
--}
--
--static bool is_supported_mech(unsigned long *oid, unsigned int len,
-- int *mech_type)
--{
-- if (!compare_oid(oid, len, MSKRB5_OID, ARRAY_SIZE(MSKRB5_OID))) {
-- *mech_type = SPNEGO_MECH_MSKRB5;
-- return true;
-- }
--
-- if (!compare_oid(oid, len, KRB5_OID, ARRAY_SIZE(KRB5_OID))) {
-- *mech_type = SPNEGO_MECH_KRB5;
-- return true;
-- }
--
-- *mech_type = SPNEGO_MAX_MECHS;
-- return false;
--}
--
--static int decode_asn1_header(struct asn1_ctx *ctx, unsigned char **end,
-- unsigned int cls, unsigned int con, unsigned int tag)
--{
-- unsigned int d_cls, d_con, d_tag;
--
-- if (asn1_header_decode(ctx, end, &d_cls, &d_con, &d_tag) == 0 ||
-- (d_cls != cls || d_con != con || d_tag != tag))
-- return -EINVAL;
-- return 0;
--}
--
--static int decode_negTokenInit(unsigned char *negToken, int token_len,
-- int *mech_type, unsigned char **krb5_ap_req,
-- unsigned int *req_len)
--{
-- struct asn1_ctx ctx;
-- unsigned char *end, *mech_types_end, *id;
-- unsigned long *oid = NULL;
-- unsigned int len;
--
-- asn1_open(&ctx, negToken, token_len);
--
-- /* GSSAPI header */
-- if (decode_asn1_header(&ctx, &end, ASN1_APL, ASN1_CON, ASN1_EOC)) {
-- pr_debug("Error decoding SPNEGO application tag\n");
-- return -EINVAL;
-- }
--
-- /* SPNEGO oid */
-- if (decode_asn1_header(&ctx, &end, ASN1_UNI, ASN1_PRI, ASN1_OJI) ||
-- asn1_oid_decode(&ctx, end, &oid, &len) == 0 ||
-- compare_oid(oid, len, SPNEGO_OID, SPNEGO_OID_LEN)) {
-- pr_debug("Error decoding SPNEGO OID\n");
-- g_free(oid);
-- return -EINVAL;
-- }
-- g_free(oid);
--
-- /* negoTokenInit */
-- if (decode_asn1_header(&ctx, &end, ASN1_CTX, ASN1_CON, 0) ||
-- decode_asn1_header(&ctx, &end,
-- ASN1_UNI, ASN1_CON, ASN1_SEQ)) {
-- pr_debug("Error decoding negTokenInit tag\n");
-- return -EINVAL;
-- }
--
-- /* mechTypes */
-- if (decode_asn1_header(&ctx, &end, ASN1_CTX, ASN1_CON, 0) ||
-- decode_asn1_header(&ctx, &end,
-- ASN1_UNI, ASN1_CON, ASN1_SEQ)) {
-- pr_debug("Error decoding mechTypes tag\n");
-- return -EINVAL;
-- }
--
-- mech_types_end = end;
-- if (decode_asn1_header(&ctx, &end, ASN1_UNI, ASN1_PRI, ASN1_OJI) ||
-- asn1_oid_decode(&ctx, end, &oid, &len) == 0) {
-- pr_debug("Error decoding Kerberos 5 OIDs\n");
-- return -EINVAL;
-- }
--
-- if (!is_supported_mech(oid, len, mech_type)) {
-- g_free(oid);
-- pr_debug("Not a supported mechanism\n");
-- return -EINVAL;
-- }
-- g_free(oid);
--
-- ctx.pointer = mech_types_end;
-- /* mechToken */
-- if (decode_asn1_header(&ctx, &end, ASN1_CTX, ASN1_CON, 2) ||
-- decode_asn1_header(&ctx, &end,
-- ASN1_UNI, ASN1_PRI, ASN1_OTS)) {
-- pr_debug("Error decoding krb5_blob\n");
-- return -EINVAL;
-- }
--
-- if (decode_asn1_header(&ctx, &end, ASN1_APL, ASN1_CON, ASN1_EOC)) {
-- pr_debug("Error decoding GSSAPI application tag\n");
-- return -EINVAL;
-- }
--
-- /* Kerberos 5 oid */
-- if (decode_asn1_header(&ctx, &end, ASN1_UNI, ASN1_PRI, ASN1_OJI)) {
-- pr_debug("Error decoding Kerberos 5 OID tag\n");
-- return -EINVAL;
-- }
--
-- if (asn1_oid_decode(&ctx, end, &oid, &len) == 0 ||
-- compare_oid(oid, len, KRB5_OID,
-- ARRAY_SIZE(KRB5_OID))) {
-- pr_debug("Not a Kerberos 5 OID\n");
-- g_free(oid);
-- return -EINVAL;
-- }
-- g_free(oid);
--
-- /* AP_REQ id */
-- if (asn1_read(&ctx, &id, 2) == 0 || id[0] != 1 || id[1] != 0) {
-- if (id)
-- free(id);
-- pr_debug("Error decoding AP_REQ ID\n");
-- return -EINVAL;
-- }
-- free(id);
--
-- /* AP_REQ */
-- *req_len = (unsigned int)(ctx.end - ctx.pointer);
-- *krb5_ap_req = ctx.pointer;
-- return 0;
--}
--
--static int encode_negTokenTarg(char *in_blob, int in_len,
-- const unsigned long *oid, int oid_len,
-- char **out_blob, int *out_len)
--{
-- unsigned char *buf;
-- unsigned char *sup_oid, *krb5_oid;
-- int sup_oid_len, krb5_oid_len;
-- unsigned int neg_result_len, sup_mech_len, rep_token_len, len;
--
-- if (asn1_oid_encode(oid, oid_len, &sup_oid, &sup_oid_len))
-- return -ENOMEM;
-- if (asn1_oid_encode(KRB5_OID, ARRAY_SIZE(KRB5_OID),
-- &krb5_oid, &krb5_oid_len)) {
-- g_free(sup_oid);
-- return -ENOMEM;
-- }
--
-- neg_result_len = asn1_header_len(1, 2);
-- sup_mech_len = asn1_header_len(sup_oid_len, 2);
-- rep_token_len = asn1_header_len(krb5_oid_len, 1);
-- rep_token_len += 2 + in_len;
-- rep_token_len = asn1_header_len(rep_token_len, 3);
--
-- *out_len = asn1_header_len(
-- neg_result_len + sup_mech_len + rep_token_len, 2);
-- *out_blob = g_try_malloc0(*out_len);
-- if (*out_blob == NULL)
-- return -ENOMEM;
-- buf = *out_blob;
--
-- /* negTokenTarg */
-- len = *out_len;
-- asn1_header_encode(&buf,
-- ASN1_CTX, ASN1_CON, 1,
-- &len);
-- asn1_header_encode(&buf,
-- ASN1_UNI, ASN1_CON, ASN1_SEQ,
-- &len);
--
-- /* negTokenTarg/negResult */
-- len = neg_result_len;
-- asn1_header_encode(&buf,
-- ASN1_CTX, ASN1_CON, 0,
-- &len);
-- asn1_header_encode(&buf,
-- ASN1_UNI, ASN1_PRI, ASN1_ENUM,
-- &len);
-- *buf++ = 0;
--
-- /* negTokenTarg/supportedMechType */
-- len = sup_mech_len;
-- asn1_header_encode(&buf,
-- ASN1_CTX, ASN1_CON, 1,
-- &len);
-- asn1_header_encode(&buf,
-- ASN1_UNI, ASN1_PRI, ASN1_OJI,
-- &len);
-- memcpy(buf, sup_oid, sup_oid_len);
-- buf += len;
--
-- /* negTokenTarg/responseToken */
-- len = rep_token_len;
-- asn1_header_encode(&buf,
-- ASN1_CTX, ASN1_CON, 2,
-- &len);
-- asn1_header_encode(&buf,
-- ASN1_UNI, ASN1_PRI, ASN1_OTS,
-- &len);
-- asn1_header_encode(&buf,
-- ASN1_APL, ASN1_CON, 0,
-- &len);
-- /* negTokenTarg/responseToken/OID */
-- len = asn1_header_len(krb5_oid_len, 1);
-- asn1_header_encode(&buf,
-- ASN1_UNI, ASN1_PRI, ASN1_OJI,
-- &len);
-- /* negTokenTarg/responseToken/mechToken*/
-- memcpy(buf, krb5_oid, krb5_oid_len);
-- buf += len;
-- /* AP_REP id */
-- *buf++ = 2;
-- *buf++ = 0;
-- memcpy(buf, in_blob, in_len);
--
-- g_free(sup_oid);
-- g_free(krb5_oid);
--}
--
--int spnego_handle_authen_request(struct ksmbd_spnego_authen_request *req,
-- struct ksmbd_spnego_auth_out *auth_out)
--{
-- struct spnego_mech_ctx *mech_ctx;
-- unsigned char *mech_token;
-- int token_len, mech_type;
-- int retval = 0;
--
-- if (decode_negTokenInit(req->spnego_blob, (int)req->spnego_blob_len,
-- &mech_type, &mech_token, &token_len)) {
-- pr_info("Error decoding negTokenInit\n");
-- return -EINVAL;
-- }
--
-- mech_ctx = get_mech(mech_type);
-- if (!mech_ctx) {
-- retval = -ENOTSUP;
-- pr_info("No support for Kerberos 5\n");
-- goto out;
-- }
--
-- if (mech_ctx->ops->handle_authen(mech_ctx,
-- mech_token, token_len,
-- auth_out, encode_negTokenTarg)) {
-- retval = -EPERM;
-- pr_info("Error authenticating\n");
-- goto out;
-- }
--out:
-- return retval;
--}
---- /dev/null
-+++ b/tools/management/spnego.c
-@@ -0,0 +1,348 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+/*
-+ * Copyright (C) 2020 LG Electronics
-+ *
-+ * linux-cifsd-devel@lists.sourceforge.net
-+ */
-+
-+#include "tools.h"
-+
-+#ifndef _GNU_SOURCE
-+#define _GNU_SOURCE
-+#endif
-+
-+#include <stdlib.h>
-+#include <stdio.h>
-+#include <unistd.h>
-+#include <sys/types.h>
-+#include <fcntl.h>
-+#include <stdint.h>
-+#include <stdbool.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];
-+
-+static struct spnego_mech_ctx *get_mech(int mech_type)
-+{
-+ if (mech_type >= SPNEGO_MAX_MECHS)
-+ return NULL;
-+ return &mech_ctxs[mech_type];
-+}
-+
-+int spnego_init(void)
-+{
-+ struct spnego_mech_ctx *mech_ctx;
-+ int i;
-+
-+ mech_ctx = &mech_ctxs[SPNEGO_MECH_MSKRB5];
-+ mech_ctx->ops = &spnego_mskrb5_operations;
-+ if (global_conf.krb5_service_name)
-+ mech_ctx->params.krb5.service_name =
-+ strdup(global_conf.krb5_service_name);
-+ if (global_conf.krb5_keytab_file)
-+ mech_ctx->params.krb5.keytab_name =
-+ strdup(global_conf.krb5_keytab_file);
-+
-+ mech_ctx = &mech_ctxs[SPNEGO_MECH_KRB5];
-+ mech_ctx->ops = &spnego_krb5_operations;
-+ if (global_conf.krb5_service_name)
-+ mech_ctx->params.krb5.service_name =
-+ strdup(global_conf.krb5_service_name);
-+ if (global_conf.krb5_keytab_file)
-+ mech_ctx->params.krb5.keytab_name =
-+ strdup(global_conf.krb5_keytab_file);
-+
-+ for (i = 0; i < SPNEGO_MAX_MECHS; i++) {
-+ if (mech_ctxs[i].ops->setup &&
-+ mech_ctxs[i].ops->setup(&mech_ctxs[i])) {
-+ pr_err("Failed to init Kerberos 5\n");
-+ goto out_err;
-+ }
-+ }
-+
-+ return 0;
-+out_err:
-+ for (; i >= 0; i--) {
-+ if (mech_ctxs[i].ops->cleanup)
-+ mech_ctxs[i].ops->cleanup(&mech_ctxs[i]);
-+ }
-+ return -ENOTSUP;
-+}
-+
-+void spnego_destroy(void)
-+{
-+ int i;
-+
-+ for (i = 0; i < SPNEGO_MAX_MECHS; i++) {
-+ if (mech_ctxs[i].ops && mech_ctxs[i].ops->cleanup)
-+ mech_ctxs[i].ops->cleanup(&mech_ctxs[i]);
-+ }
-+}
-+
-+static int compare_oid(unsigned long *oid1, unsigned int oid1len,
-+ unsigned long *oid2, unsigned int oid2len)
-+{
-+ unsigned int i;
-+
-+ if (oid1len != oid2len)
-+ return 1;
-+
-+ for (i = 0; i < oid1len; i++) {
-+ if (oid1[i] != oid2[i])
-+ return 1;
-+ }
-+ return 0;
-+}
-+
-+static bool is_supported_mech(unsigned long *oid, unsigned int len,
-+ int *mech_type)
-+{
-+ if (!compare_oid(oid, len, MSKRB5_OID, ARRAY_SIZE(MSKRB5_OID))) {
-+ *mech_type = SPNEGO_MECH_MSKRB5;
-+ return true;
-+ }
-+
-+ if (!compare_oid(oid, len, KRB5_OID, ARRAY_SIZE(KRB5_OID))) {
-+ *mech_type = SPNEGO_MECH_KRB5;
-+ return true;
-+ }
-+
-+ *mech_type = SPNEGO_MAX_MECHS;
-+ return false;
-+}
-+
-+static int decode_asn1_header(struct asn1_ctx *ctx, unsigned char **end,
-+ unsigned int cls, unsigned int con, unsigned int tag)
-+{
-+ unsigned int d_cls, d_con, d_tag;
-+
-+ if (asn1_header_decode(ctx, end, &d_cls, &d_con, &d_tag) == 0 ||
-+ (d_cls != cls || d_con != con || d_tag != tag))
-+ return -EINVAL;
-+ return 0;
-+}
-+
-+static int decode_negTokenInit(unsigned char *negToken, int token_len,
-+ int *mech_type, unsigned char **krb5_ap_req,
-+ unsigned int *req_len)
-+{
-+ struct asn1_ctx ctx;
-+ unsigned char *end, *mech_types_end, *id;
-+ unsigned long *oid = NULL;
-+ unsigned int len;
-+
-+ asn1_open(&ctx, negToken, token_len);
-+
-+ /* GSSAPI header */
-+ if (decode_asn1_header(&ctx, &end, ASN1_APL, ASN1_CON, ASN1_EOC)) {
-+ pr_debug("Error decoding SPNEGO application tag\n");
-+ return -EINVAL;
-+ }
-+
-+ /* SPNEGO oid */
-+ if (decode_asn1_header(&ctx, &end, ASN1_UNI, ASN1_PRI, ASN1_OJI) ||
-+ asn1_oid_decode(&ctx, end, &oid, &len) == 0 ||
-+ compare_oid(oid, len, SPNEGO_OID, SPNEGO_OID_LEN)) {
-+ pr_debug("Error decoding SPNEGO OID\n");
-+ g_free(oid);
-+ return -EINVAL;
-+ }
-+ g_free(oid);
-+
-+ /* negoTokenInit */
-+ if (decode_asn1_header(&ctx, &end, ASN1_CTX, ASN1_CON, 0) ||
-+ decode_asn1_header(&ctx, &end,
-+ ASN1_UNI, ASN1_CON, ASN1_SEQ)) {
-+ pr_debug("Error decoding negTokenInit tag\n");
-+ return -EINVAL;
-+ }
-+
-+ /* mechTypes */
-+ if (decode_asn1_header(&ctx, &end, ASN1_CTX, ASN1_CON, 0) ||
-+ decode_asn1_header(&ctx, &end,
-+ ASN1_UNI, ASN1_CON, ASN1_SEQ)) {
-+ pr_debug("Error decoding mechTypes tag\n");
-+ return -EINVAL;
-+ }
-+
-+ mech_types_end = end;
-+ if (decode_asn1_header(&ctx, &end, ASN1_UNI, ASN1_PRI, ASN1_OJI) ||
-+ asn1_oid_decode(&ctx, end, &oid, &len) == 0) {
-+ pr_debug("Error decoding Kerberos 5 OIDs\n");
-+ return -EINVAL;
-+ }
-+
-+ if (!is_supported_mech(oid, len, mech_type)) {
-+ g_free(oid);
-+ pr_debug("Not a supported mechanism\n");
-+ return -EINVAL;
-+ }
-+ g_free(oid);
-+
-+ ctx.pointer = mech_types_end;
-+ /* mechToken */
-+ if (decode_asn1_header(&ctx, &end, ASN1_CTX, ASN1_CON, 2) ||
-+ decode_asn1_header(&ctx, &end,
-+ ASN1_UNI, ASN1_PRI, ASN1_OTS)) {
-+ pr_debug("Error decoding krb5_blob\n");
-+ return -EINVAL;
-+ }
-+
-+ if (decode_asn1_header(&ctx, &end, ASN1_APL, ASN1_CON, ASN1_EOC)) {
-+ pr_debug("Error decoding GSSAPI application tag\n");
-+ return -EINVAL;
-+ }
-+
-+ /* Kerberos 5 oid */
-+ if (decode_asn1_header(&ctx, &end, ASN1_UNI, ASN1_PRI, ASN1_OJI)) {
-+ pr_debug("Error decoding Kerberos 5 OID tag\n");
-+ return -EINVAL;
-+ }
-+
-+ if (asn1_oid_decode(&ctx, end, &oid, &len) == 0 ||
-+ compare_oid(oid, len, KRB5_OID,
-+ ARRAY_SIZE(KRB5_OID))) {
-+ pr_debug("Not a Kerberos 5 OID\n");
-+ g_free(oid);
-+ return -EINVAL;
-+ }
-+ g_free(oid);
-+
-+ /* AP_REQ id */
-+ if (asn1_read(&ctx, &id, 2) == 0 || id[0] != 1 || id[1] != 0) {
-+ if (id)
-+ free(id);
-+ pr_debug("Error decoding AP_REQ ID\n");
-+ return -EINVAL;
-+ }
-+ free(id);
-+
-+ /* AP_REQ */
-+ *req_len = (unsigned int)(ctx.end - ctx.pointer);
-+ *krb5_ap_req = ctx.pointer;
-+ return 0;
-+}
-+
-+static int encode_negTokenTarg(char *in_blob, int in_len,
-+ const unsigned long *oid, int oid_len,
-+ char **out_blob, int *out_len)
-+{
-+ unsigned char *buf;
-+ unsigned char *sup_oid, *krb5_oid;
-+ int sup_oid_len, krb5_oid_len;
-+ unsigned int neg_result_len, sup_mech_len, rep_token_len, len;
-+
-+ if (asn1_oid_encode(oid, oid_len, &sup_oid, &sup_oid_len))
-+ return -ENOMEM;
-+ if (asn1_oid_encode(KRB5_OID, ARRAY_SIZE(KRB5_OID),
-+ &krb5_oid, &krb5_oid_len)) {
-+ g_free(sup_oid);
-+ return -ENOMEM;
-+ }
-+
-+ neg_result_len = asn1_header_len(1, 2);
-+ sup_mech_len = asn1_header_len(sup_oid_len, 2);
-+ rep_token_len = asn1_header_len(krb5_oid_len, 1);
-+ rep_token_len += 2 + in_len;
-+ rep_token_len = asn1_header_len(rep_token_len, 3);
-+
-+ *out_len = asn1_header_len(
-+ neg_result_len + sup_mech_len + rep_token_len, 2);
-+ *out_blob = g_try_malloc0(*out_len);
-+ if (*out_blob == NULL)
-+ return -ENOMEM;
-+ buf = *out_blob;
-+
-+ /* negTokenTarg */
-+ len = *out_len;
-+ asn1_header_encode(&buf,
-+ ASN1_CTX, ASN1_CON, 1,
-+ &len);
-+ asn1_header_encode(&buf,
-+ ASN1_UNI, ASN1_CON, ASN1_SEQ,
-+ &len);
-+
-+ /* negTokenTarg/negResult */
-+ len = neg_result_len;
-+ asn1_header_encode(&buf,
-+ ASN1_CTX, ASN1_CON, 0,
-+ &len);
-+ asn1_header_encode(&buf,
-+ ASN1_UNI, ASN1_PRI, ASN1_ENUM,
-+ &len);
-+ *buf++ = 0;
-+
-+ /* negTokenTarg/supportedMechType */
-+ len = sup_mech_len;
-+ asn1_header_encode(&buf,
-+ ASN1_CTX, ASN1_CON, 1,
-+ &len);
-+ asn1_header_encode(&buf,
-+ ASN1_UNI, ASN1_PRI, ASN1_OJI,
-+ &len);
-+ memcpy(buf, sup_oid, sup_oid_len);
-+ buf += len;
-+
-+ /* negTokenTarg/responseToken */
-+ len = rep_token_len;
-+ asn1_header_encode(&buf,
-+ ASN1_CTX, ASN1_CON, 2,
-+ &len);
-+ asn1_header_encode(&buf,
-+ ASN1_UNI, ASN1_PRI, ASN1_OTS,
-+ &len);
-+ asn1_header_encode(&buf,
-+ ASN1_APL, ASN1_CON, 0,
-+ &len);
-+ /* negTokenTarg/responseToken/OID */
-+ len = asn1_header_len(krb5_oid_len, 1);
-+ asn1_header_encode(&buf,
-+ ASN1_UNI, ASN1_PRI, ASN1_OJI,
-+ &len);
-+ /* negTokenTarg/responseToken/mechToken*/
-+ memcpy(buf, krb5_oid, krb5_oid_len);
-+ buf += len;
-+ /* AP_REP id */
-+ *buf++ = 2;
-+ *buf++ = 0;
-+ memcpy(buf, in_blob, in_len);
-+
-+ g_free(sup_oid);
-+ g_free(krb5_oid);
-+}
-+
-+int spnego_handle_authen_request(struct ksmbd_spnego_authen_request *req,
-+ struct ksmbd_spnego_auth_out *auth_out)
-+{
-+ struct spnego_mech_ctx *mech_ctx;
-+ unsigned char *mech_token;
-+ int token_len, mech_type;
-+ int retval = 0;
-+
-+ if (decode_negTokenInit(req->spnego_blob, (int)req->spnego_blob_len,
-+ &mech_type, &mech_token, &token_len)) {
-+ pr_info("Error decoding negTokenInit\n");
-+ return -EINVAL;
-+ }
-+
-+ mech_ctx = get_mech(mech_type);
-+ if (!mech_ctx) {
-+ retval = -ENOTSUP;
-+ pr_info("No support for Kerberos 5\n");
-+ goto out;
-+ }
-+
-+ if (mech_ctx->ops->handle_authen(mech_ctx,
-+ mech_token, token_len,
-+ auth_out, encode_negTokenTarg)) {
-+ retval = -EPERM;
-+ pr_info("Error authenticating\n");
-+ goto out;
-+ }
-+out:
-+ return retval;
-+}
---- a/lib/management/spnego_krb5.c
-+++ /dev/null
-@@ -1,408 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0-or-later
--/*
-- * Copyright (C) 2020 LG Electronics
-- *
-- * linux-cifsd-devel@lists.sourceforge.net
-- */
--
--#include "ksmbdtools.h"
--
--#include <stdlib.h>
--#include <string.h>
--#include <unistd.h>
--#include <sys/types.h>
--#include <sys/socket.h>
--#include <netdb.h>
--#include <krb5.h>
--
--#include <management/spnego.h>
--#include <asn1.h>
--#include "spnego_mech.h"
--
--#ifndef HAVE_KRB5_AUTH_CON_GETRECVSUBKEY
--krb5_error_code krb5_auth_con_getrecvsubkey(krb5_context context,
-- krb5_auth_context auth_context, krb5_keyblock **keyblock)
--{
-- return krb5_auth_con_getremotesubkey(context, auth_context, keyblock);
--}
--#endif /* HAVE_KRB5_AUTH_CON_GETRECVSUBKEY */
--
--#ifdef HAVE_KRB5_KEYBLOCK_KEYVALUE
--#define KRB5_KEY_TYPE(k) ((k)->keytype)
--#define KRB5_KEY_LENGTH(k) ((k)->keyvalue.length)
--#define KRB5_KEY_DATA(k) ((k)->keyvalue.data)
--#else
--#define KRB5_KEY_TYPE(k) ((k)->enctype)
--#define KRB5_KEY_LENGTH(k) ((k)->length)
--#define KRB5_KEY_DATA(k) ((k)->contents)
--#endif /* HAVE_KRB5_KEYBLOCK_KEYVALUE */
--
--struct spnego_krb5_ctx {
-- krb5_context context;
-- krb5_keytab keytab;
-- krb5_creds creds;
--};
--
--#define SERVICE_NAME "cifs"
--
--#define pr_krb5_err(_context, _retval, _fmt, ...) \
-- do { \
-- const char *msg = krb5_get_error_message(_context, _retval); \
-- pr_err("%s: " _fmt, msg, ##__VA_ARGS__); \
-- krb5_free_error_message(_context, msg); \
-- } while (0)
--
--static char *get_service_name(void)
--{
-- return strdup(SERVICE_NAME);
--}
--
--static char *get_host_name(void)
--{
-- struct addrinfo hint, *ai;
-- char *host_name;
-- char hostname[NI_MAXHOST];
--
-- if (gethostname(hostname, sizeof(hostname)))
-- return NULL;
--
-- memset(&hint, 0, sizeof(hint));
-- hint.ai_family = AF_UNSPEC;
-- hint.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
-- if (getaddrinfo(hostname, NULL, &hint, &ai))
-- return NULL;
--
-- host_name = strdup(ai->ai_canonname);
-- freeaddrinfo(ai);
-- return host_name;
--}
--
--/* Service full name is <service name>[/<host FQDN>[@REALM>]] */
--static int parse_service_full_name(char *service_full_name,
-- char **service_name,
-- char **host_name)
--{
-- char *name, *delim;
--
-- *service_name = NULL;
-- *host_name = NULL;
--
-- if (!service_full_name) {
-- *service_name = get_service_name();
-- *host_name = get_host_name();
-- goto out;
-- }
--
-- name = service_full_name;
-- delim = strchr(name, '/');
-- if (!delim) {
-- *service_name = strdup(name);
-- *host_name = get_host_name();
-- goto out;
-- }
-- *service_name = strndup(name, delim - name);
-- if (*service_name == NULL)
-- return -ENOMEM;
--
-- name = delim + 1;
-- delim = strchr(name, '@');
-- if (!delim) {
-- *host_name = strdup(name);
-- goto out;
-- }
-- *host_name = strndup(name, delim - name);
-- if (*host_name == NULL) {
-- free(*service_name);
-- *service_name = NULL;
-- return -ENOMEM;
-- }
--out:
-- /* we assume the host name is FQDN if it has "." */
-- if (*host_name && strchr(*host_name, '.'))
-- return 0;
--
-- free(*service_name);
-- free(*host_name);
-- *service_name = NULL;
-- *host_name = NULL;
-- return -EINVAL;
--}
--
--static krb5_error_code acquire_creds_from_keytab(krb5_context context,
-- char *service_full_name, char *keytab_name,
-- krb5_creds *out_creds, krb5_keytab *keytab)
--{
-- krb5_error_code retval;
-- krb5_principal sprinc = NULL;
-- char *host_name = NULL, *service_name = NULL;
--
-- if (keytab_name)
-- retval = krb5_kt_resolve(context, keytab_name, keytab);
-- else
-- retval = krb5_kt_default(context, keytab);
-- if (retval) {
-- pr_krb5_err(context, retval, "while resolving keytab\n");
-- return retval;
-- }
--
-- if (parse_service_full_name(service_full_name,
-- &service_name, &host_name)) {
-- retval = KRB5_ERR_HOST_REALM_UNKNOWN;
-- pr_krb5_err(context, retval, "while getting host name\n");
-- goto out_err;
-- }
--
-- retval = krb5_sname_to_principal(context, host_name, service_name,
-- KRB5_NT_UNKNOWN, &sprinc);
-- if (retval) {
-- pr_krb5_err(context, retval, "while generating service name\n");
-- goto out_err;
-- }
--
-- retval = krb5_get_init_creds_keytab(context, out_creds, sprinc,
-- *keytab, 0, NULL, NULL);
-- if (retval) {
-- char *name;
--
-- krb5_unparse_name(context, sprinc, &name);
-- pr_krb5_err(context, retval,
-- "while getting credentials for %s\n", name);
-- krb5_free_unparsed_name(context, name);
-- goto out_err;
-- }
--
-- free(host_name);
-- free(service_name);
-- return 0;
--out_err:
-- if (sprinc)
-- krb5_free_principal(context, sprinc);
-- if (service_name)
-- free(service_name);
-- if (host_name)
-- free(host_name);
-- if (*keytab)
-- krb5_kt_close(context, *keytab);
-- return retval;
--}
--
--static int handle_krb5_authen(struct spnego_mech_ctx *mech_ctx,
-- char *in_blob, unsigned int in_len,
-- struct ksmbd_spnego_auth_out *auth_out,
-- spnego_encode_t spnego_encode)
--{
-- struct spnego_krb5_ctx *krb5_ctx;
-- char *client_name;
-- krb5_auth_context auth_context;
-- krb5_data packet, ap_rep;
-- krb5_ticket *ticket = NULL;
-- krb5_keyblock *session_key;
--#ifdef HAVE_KRB5_AUTH_CON_GETAUTHENTICATOR_DOUBLE_POINTER
-- krb5_authenticator *authenti;
--#else
-- krb5_authenticator authenti;
--#endif /* HAVE_KRB5_AUTH_CON_GETAUTHENTICATOR_DOUBLE_POINTER */
-- krb5_principal client;
-- int retval = -EINVAL;
-- krb5_error_code krb_retval;
--
-- krb5_ctx = (struct spnego_krb5_ctx *)mech_ctx->private;
-- if (!krb5_ctx)
-- return -EINVAL;
--
-- krb_retval = krb5_auth_con_init(krb5_ctx->context, &auth_context);
-- if (krb_retval) {
-- pr_krb5_err(krb5_ctx->context, krb_retval,
-- "while initializing auth context\n");
-- return -EINVAL;
-- }
--
-- packet.length = in_len;
-- packet.data = (krb5_pointer)in_blob;
-- krb_retval = krb5_rd_req(krb5_ctx->context, &auth_context, &packet,
-- krb5_ctx->creds.client, krb5_ctx->keytab,
-- NULL, &ticket);
-- if (krb_retval) {
-- char *name;
--
-- krb5_unparse_name(krb5_ctx->context, krb5_ctx->creds.client,
-- &name);
-- krb5_auth_con_free(krb5_ctx->context, auth_context);
-- pr_krb5_err(krb5_ctx->context, krb_retval,
-- "while decoding AP_REQ with %s creds\n", name);
-- krb5_free_unparsed_name(krb5_ctx->context, name);
-- return -EINVAL;
-- }
--
-- krb_retval = krb5_auth_con_getrecvsubkey(krb5_ctx->context,
-- auth_context, &session_key);
-- if (krb_retval) {
-- pr_krb5_err(krb5_ctx->context, krb_retval,
-- "while reading session key\n");
-- goto out_free_con_auth;
-- }
--
-- krb_retval = krb5_mk_rep(krb5_ctx->context, auth_context, &ap_rep);
-- if (krb_retval) {
-- pr_krb5_err(krb5_ctx->context, krb_retval,
-- "while making AP_REP\n");
-- goto out_free_key;
-- }
--
-- krb_retval = krb5_auth_con_getauthenticator(krb5_ctx->context,
-- auth_context, &authenti);
-- if (krb_retval) {
-- pr_krb5_err(krb5_ctx->context, krb_retval,
-- "while getting authenticator\n");
-- goto out_free_rep;
-- }
--
--#ifndef HAVE_KRB5_AUTHENTICATOR_CLIENT
-- krb_retval = krb5_build_principal_ext(krb5_ctx->context, &client,
-- strlen(authenti->crealm), authenti->crealm, 0);
-- if (krb_retval) {
-- pr_krb5_err(krb5_ctx->context, krb_retval,
-- "while getting authenticator client\n");
-- goto out_free_auth;
-- }
-- krb_retval = copy_PrincipalName(&authenti->cname, &client->name);
-- if (krb_retval) {
-- pr_krb5_err(krb5_ctx->context, krb_retval,
-- "while copying authenticator client name\n");
-- goto out_free_client;
-- }
--#else
-- client = authenti->client;
--#endif /* HAVE_KRB5_AUTHENTICATOR_CLIENT */
--
-- krb_retval = krb5_unparse_name_flags(krb5_ctx->context,
-- client,
-- KRB5_PRINCIPAL_UNPARSE_NO_REALM, &client_name);
-- if (krb_retval) {
-- pr_krb5_err(krb5_ctx->context, krb_retval,
-- "while unparsing client name\n");
-- goto out_free_client;
-- }
--
-- memset(auth_out, 0, sizeof(*auth_out));
-- auth_out->user_name = strdup(client_name);
-- if (!auth_out->user_name) {
-- krb5_free_unparsed_name(krb5_ctx->context, client_name);
-- retval = -ENOMEM;
-- goto out_free_client;
-- }
-- krb5_free_unparsed_name(krb5_ctx->context, client_name);
--
-- auth_out->sess_key = malloc(KRB5_KEY_LENGTH(session_key));
-- if (!auth_out->sess_key) {
-- free(auth_out->user_name);
-- retval = -ENOMEM;
-- goto out_free_client;
-- }
-- memcpy(auth_out->sess_key, KRB5_KEY_DATA(session_key), KRB5_KEY_LENGTH(session_key));
-- auth_out->key_len = KRB5_KEY_LENGTH(session_key);
--
-- if (spnego_encode(ap_rep.data, ap_rep.length,
-- mech_ctx->oid, mech_ctx->oid_len,
-- &auth_out->spnego_blob, &auth_out->blob_len)) {
-- free(auth_out->user_name);
-- free(auth_out->sess_key);
-- goto out_free_client;
-- }
--
-- pr_info("Authenticated user `%s'\n", auth_out->user_name);
-- retval = 0;
--
--out_free_client:
--#ifndef HAVE_KRB5_AUTHENTICATOR_CLIENT
-- krb5_free_principal(krb5_ctx->context, client);
--#endif /* HAVE_KRB5_AUTHENTICATOR_CLIENT */
--out_free_auth:
--#ifdef HAVE_KRB5_AUTH_CON_GETAUTHENTICATOR_DOUBLE_POINTER
-- krb5_free_authenticator(krb5_ctx->context, authenti);
--#else
-- krb5_free_authenticator(krb5_ctx->context, &authenti);
--#endif /* HAVE_KRB5_AUTH_CON_GETAUTHENTICATOR_DOUBLE_POINTER */
--out_free_rep:
-- krb5_free_data_contents(krb5_ctx->context, &ap_rep);
--out_free_key:
-- krb5_free_keyblock(krb5_ctx->context, session_key);
--out_free_con_auth:
-- krb5_free_ticket(krb5_ctx->context, ticket);
-- krb5_auth_con_free(krb5_ctx->context, auth_context);
-- return retval;
--}
--
--static int setup_krb5_ctx(struct spnego_mech_ctx *mech_ctx)
--{
-- struct spnego_krb5_ctx *krb5_ctx;
-- krb5_error_code krb_retval;
--
-- krb5_ctx = g_try_malloc0(sizeof(*krb5_ctx));
-- if (!krb5_ctx)
-- return -ENOMEM;
--
-- krb_retval = krb5_init_context(&krb5_ctx->context);
-- if (krb_retval) {
-- g_free(krb5_ctx);
-- pr_err("while initializing krb5 context\n");
-- return -EINVAL;
-- }
--
-- krb_retval = acquire_creds_from_keytab(krb5_ctx->context,
-- mech_ctx->params.krb5.service_name,
-- mech_ctx->params.krb5.keytab_name,
-- &krb5_ctx->creds, &krb5_ctx->keytab);
-- if (krb_retval) {
-- krb5_free_context(krb5_ctx->context);
-- g_free(krb5_ctx);
-- return -EINVAL;
-- }
--
-- mech_ctx->private = krb5_ctx;
-- return 0;
--}
--
--static int setup_krb5(struct spnego_mech_ctx *mech_ctx)
--{
-- mech_ctx->oid = KRB5_OID;
-- mech_ctx->oid_len = ARRAY_SIZE(KRB5_OID);
-- return setup_krb5_ctx(mech_ctx);
--}
--
--static int setup_mskrb5(struct spnego_mech_ctx *mech_ctx)
--{
-- mech_ctx->oid = MSKRB5_OID;
-- mech_ctx->oid_len = ARRAY_SIZE(MSKRB5_OID);
-- return setup_krb5_ctx(mech_ctx);
--}
--
--static void cleanup_krb5(struct spnego_mech_ctx *mech_ctx)
--{
-- if (mech_ctx->private) {
-- struct spnego_krb5_ctx *krb5_ctx;
--
-- krb5_ctx = (struct spnego_krb5_ctx *)mech_ctx->private;
-- krb5_free_cred_contents(krb5_ctx->context, &krb5_ctx->creds);
-- krb5_kt_close(krb5_ctx->context, krb5_ctx->keytab);
-- krb5_free_context(krb5_ctx->context);
-- g_free(krb5_ctx);
-- mech_ctx->private = NULL;
-- }
-- if (mech_ctx->params.krb5.service_name)
-- free(mech_ctx->params.krb5.service_name);
-- if (mech_ctx->params.krb5.keytab_name)
-- free(mech_ctx->params.krb5.keytab_name);
--}
--
--struct spnego_mech_operations spnego_krb5_operations = {
-- .setup = setup_krb5,
-- .cleanup = cleanup_krb5,
-- .handle_authen = handle_krb5_authen,
--};
--
--struct spnego_mech_operations spnego_mskrb5_operations = {
-- .setup = setup_mskrb5,
-- .cleanup = cleanup_krb5,
-- .handle_authen = handle_krb5_authen,
--};
---- /dev/null
-+++ b/tools/management/spnego_krb5.c
-@@ -0,0 +1,408 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+/*
-+ * Copyright (C) 2020 LG Electronics
-+ *
-+ * linux-cifsd-devel@lists.sourceforge.net
-+ */
-+
-+#include "tools.h"
-+
-+#include <stdlib.h>
-+#include <string.h>
-+#include <unistd.h>
-+#include <sys/types.h>
-+#include <sys/socket.h>
-+#include <netdb.h>
-+#include <krb5.h>
-+
-+#include <management/spnego.h>
-+#include <asn1.h>
-+#include "spnego_mech.h"
-+
-+#ifndef HAVE_KRB5_AUTH_CON_GETRECVSUBKEY
-+krb5_error_code krb5_auth_con_getrecvsubkey(krb5_context context,
-+ krb5_auth_context auth_context, krb5_keyblock **keyblock)
-+{
-+ return krb5_auth_con_getremotesubkey(context, auth_context, keyblock);
-+}
-+#endif /* HAVE_KRB5_AUTH_CON_GETRECVSUBKEY */
-+
-+#ifdef HAVE_KRB5_KEYBLOCK_KEYVALUE
-+#define KRB5_KEY_TYPE(k) ((k)->keytype)
-+#define KRB5_KEY_LENGTH(k) ((k)->keyvalue.length)
-+#define KRB5_KEY_DATA(k) ((k)->keyvalue.data)
-+#else
-+#define KRB5_KEY_TYPE(k) ((k)->enctype)
-+#define KRB5_KEY_LENGTH(k) ((k)->length)
-+#define KRB5_KEY_DATA(k) ((k)->contents)
-+#endif /* HAVE_KRB5_KEYBLOCK_KEYVALUE */
-+
-+struct spnego_krb5_ctx {
-+ krb5_context context;
-+ krb5_keytab keytab;
-+ krb5_creds creds;
-+};
-+
-+#define SERVICE_NAME "cifs"
-+
-+#define pr_krb5_err(_context, _retval, _fmt, ...) \
-+ do { \
-+ const char *msg = krb5_get_error_message(_context, _retval); \
-+ pr_err("%s: " _fmt, msg, ##__VA_ARGS__); \
-+ krb5_free_error_message(_context, msg); \
-+ } while (0)
-+
-+static char *get_service_name(void)
-+{
-+ return strdup(SERVICE_NAME);
-+}
-+
-+static char *get_host_name(void)
-+{
-+ struct addrinfo hint, *ai;
-+ char *host_name;
-+ char hostname[NI_MAXHOST];
-+
-+ if (gethostname(hostname, sizeof(hostname)))
-+ return NULL;
-+
-+ memset(&hint, 0, sizeof(hint));
-+ hint.ai_family = AF_UNSPEC;
-+ hint.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
-+ if (getaddrinfo(hostname, NULL, &hint, &ai))
-+ return NULL;
-+
-+ host_name = strdup(ai->ai_canonname);
-+ freeaddrinfo(ai);
-+ return host_name;
-+}
-+
-+/* Service full name is <service name>[/<host FQDN>[@REALM>]] */
-+static int parse_service_full_name(char *service_full_name,
-+ char **service_name,
-+ char **host_name)
-+{
-+ char *name, *delim;
-+
-+ *service_name = NULL;
-+ *host_name = NULL;
-+
-+ if (!service_full_name) {
-+ *service_name = get_service_name();
-+ *host_name = get_host_name();
-+ goto out;
-+ }
-+
-+ name = service_full_name;
-+ delim = strchr(name, '/');
-+ if (!delim) {
-+ *service_name = strdup(name);
-+ *host_name = get_host_name();
-+ goto out;
-+ }
-+ *service_name = strndup(name, delim - name);
-+ if (*service_name == NULL)
-+ return -ENOMEM;
-+
-+ name = delim + 1;
-+ delim = strchr(name, '@');
-+ if (!delim) {
-+ *host_name = strdup(name);
-+ goto out;
-+ }
-+ *host_name = strndup(name, delim - name);
-+ if (*host_name == NULL) {
-+ free(*service_name);
-+ *service_name = NULL;
-+ return -ENOMEM;
-+ }
-+out:
-+ /* we assume the host name is FQDN if it has "." */
-+ if (*host_name && strchr(*host_name, '.'))
-+ return 0;
-+
-+ free(*service_name);
-+ free(*host_name);
-+ *service_name = NULL;
-+ *host_name = NULL;
-+ return -EINVAL;
-+}
-+
-+static krb5_error_code acquire_creds_from_keytab(krb5_context context,
-+ char *service_full_name, char *keytab_name,
-+ krb5_creds *out_creds, krb5_keytab *keytab)
-+{
-+ krb5_error_code retval;
-+ krb5_principal sprinc = NULL;
-+ char *host_name = NULL, *service_name = NULL;
-+
-+ if (keytab_name)
-+ retval = krb5_kt_resolve(context, keytab_name, keytab);
-+ else
-+ retval = krb5_kt_default(context, keytab);
-+ if (retval) {
-+ pr_krb5_err(context, retval, "while resolving keytab\n");
-+ return retval;
-+ }
-+
-+ if (parse_service_full_name(service_full_name,
-+ &service_name, &host_name)) {
-+ retval = KRB5_ERR_HOST_REALM_UNKNOWN;
-+ pr_krb5_err(context, retval, "while getting host name\n");
-+ goto out_err;
-+ }
-+
-+ retval = krb5_sname_to_principal(context, host_name, service_name,
-+ KRB5_NT_UNKNOWN, &sprinc);
-+ if (retval) {
-+ pr_krb5_err(context, retval, "while generating service name\n");
-+ goto out_err;
-+ }
-+
-+ retval = krb5_get_init_creds_keytab(context, out_creds, sprinc,
-+ *keytab, 0, NULL, NULL);
-+ if (retval) {
-+ char *name;
-+
-+ krb5_unparse_name(context, sprinc, &name);
-+ pr_krb5_err(context, retval,
-+ "while getting credentials for %s\n", name);
-+ krb5_free_unparsed_name(context, name);
-+ goto out_err;
-+ }
-+
-+ free(host_name);
-+ free(service_name);
-+ return 0;
-+out_err:
-+ if (sprinc)
-+ krb5_free_principal(context, sprinc);
-+ if (service_name)
-+ free(service_name);
-+ if (host_name)
-+ free(host_name);
-+ if (*keytab)
-+ krb5_kt_close(context, *keytab);
-+ return retval;
-+}
-+
-+static int handle_krb5_authen(struct spnego_mech_ctx *mech_ctx,
-+ char *in_blob, unsigned int in_len,
-+ struct ksmbd_spnego_auth_out *auth_out,
-+ spnego_encode_t spnego_encode)
-+{
-+ struct spnego_krb5_ctx *krb5_ctx;
-+ char *client_name;
-+ krb5_auth_context auth_context;
-+ krb5_data packet, ap_rep;
-+ krb5_ticket *ticket = NULL;
-+ krb5_keyblock *session_key;
-+#ifdef HAVE_KRB5_AUTH_CON_GETAUTHENTICATOR_DOUBLE_POINTER
-+ krb5_authenticator *authenti;
-+#else
-+ krb5_authenticator authenti;
-+#endif /* HAVE_KRB5_AUTH_CON_GETAUTHENTICATOR_DOUBLE_POINTER */
-+ krb5_principal client;
-+ int retval = -EINVAL;
-+ krb5_error_code krb_retval;
-+
-+ krb5_ctx = (struct spnego_krb5_ctx *)mech_ctx->private;
-+ if (!krb5_ctx)
-+ return -EINVAL;
-+
-+ krb_retval = krb5_auth_con_init(krb5_ctx->context, &auth_context);
-+ if (krb_retval) {
-+ pr_krb5_err(krb5_ctx->context, krb_retval,
-+ "while initializing auth context\n");
-+ return -EINVAL;
-+ }
-+
-+ packet.length = in_len;
-+ packet.data = (krb5_pointer)in_blob;
-+ krb_retval = krb5_rd_req(krb5_ctx->context, &auth_context, &packet,
-+ krb5_ctx->creds.client, krb5_ctx->keytab,
-+ NULL, &ticket);
-+ if (krb_retval) {
-+ char *name;
-+
-+ krb5_unparse_name(krb5_ctx->context, krb5_ctx->creds.client,
-+ &name);
-+ krb5_auth_con_free(krb5_ctx->context, auth_context);
-+ pr_krb5_err(krb5_ctx->context, krb_retval,
-+ "while decoding AP_REQ with %s creds\n", name);
-+ krb5_free_unparsed_name(krb5_ctx->context, name);
-+ return -EINVAL;
-+ }
-+
-+ krb_retval = krb5_auth_con_getrecvsubkey(krb5_ctx->context,
-+ auth_context, &session_key);
-+ if (krb_retval) {
-+ pr_krb5_err(krb5_ctx->context, krb_retval,
-+ "while reading session key\n");
-+ goto out_free_con_auth;
-+ }
-+
-+ krb_retval = krb5_mk_rep(krb5_ctx->context, auth_context, &ap_rep);
-+ if (krb_retval) {
-+ pr_krb5_err(krb5_ctx->context, krb_retval,
-+ "while making AP_REP\n");
-+ goto out_free_key;
-+ }
-+
-+ krb_retval = krb5_auth_con_getauthenticator(krb5_ctx->context,
-+ auth_context, &authenti);
-+ if (krb_retval) {
-+ pr_krb5_err(krb5_ctx->context, krb_retval,
-+ "while getting authenticator\n");
-+ goto out_free_rep;
-+ }
-+
-+#ifndef HAVE_KRB5_AUTHENTICATOR_CLIENT
-+ krb_retval = krb5_build_principal_ext(krb5_ctx->context, &client,
-+ strlen(authenti->crealm), authenti->crealm, 0);
-+ if (krb_retval) {
-+ pr_krb5_err(krb5_ctx->context, krb_retval,
-+ "while getting authenticator client\n");
-+ goto out_free_auth;
-+ }
-+ krb_retval = copy_PrincipalName(&authenti->cname, &client->name);
-+ if (krb_retval) {
-+ pr_krb5_err(krb5_ctx->context, krb_retval,
-+ "while copying authenticator client name\n");
-+ goto out_free_client;
-+ }
-+#else
-+ client = authenti->client;
-+#endif /* HAVE_KRB5_AUTHENTICATOR_CLIENT */
-+
-+ krb_retval = krb5_unparse_name_flags(krb5_ctx->context,
-+ client,
-+ KRB5_PRINCIPAL_UNPARSE_NO_REALM, &client_name);
-+ if (krb_retval) {
-+ pr_krb5_err(krb5_ctx->context, krb_retval,
-+ "while unparsing client name\n");
-+ goto out_free_client;
-+ }
-+
-+ memset(auth_out, 0, sizeof(*auth_out));
-+ auth_out->user_name = strdup(client_name);
-+ if (!auth_out->user_name) {
-+ krb5_free_unparsed_name(krb5_ctx->context, client_name);
-+ retval = -ENOMEM;
-+ goto out_free_client;
-+ }
-+ krb5_free_unparsed_name(krb5_ctx->context, client_name);
-+
-+ auth_out->sess_key = malloc(KRB5_KEY_LENGTH(session_key));
-+ if (!auth_out->sess_key) {
-+ free(auth_out->user_name);
-+ retval = -ENOMEM;
-+ goto out_free_client;
-+ }
-+ memcpy(auth_out->sess_key, KRB5_KEY_DATA(session_key), KRB5_KEY_LENGTH(session_key));
-+ auth_out->key_len = KRB5_KEY_LENGTH(session_key);
-+
-+ if (spnego_encode(ap_rep.data, ap_rep.length,
-+ mech_ctx->oid, mech_ctx->oid_len,
-+ &auth_out->spnego_blob, &auth_out->blob_len)) {
-+ free(auth_out->user_name);
-+ free(auth_out->sess_key);
-+ goto out_free_client;
-+ }
-+
-+ pr_info("Authenticated user `%s'\n", auth_out->user_name);
-+ retval = 0;
-+
-+out_free_client:
-+#ifndef HAVE_KRB5_AUTHENTICATOR_CLIENT
-+ krb5_free_principal(krb5_ctx->context, client);
-+#endif /* HAVE_KRB5_AUTHENTICATOR_CLIENT */
-+out_free_auth:
-+#ifdef HAVE_KRB5_AUTH_CON_GETAUTHENTICATOR_DOUBLE_POINTER
-+ krb5_free_authenticator(krb5_ctx->context, authenti);
-+#else
-+ krb5_free_authenticator(krb5_ctx->context, &authenti);
-+#endif /* HAVE_KRB5_AUTH_CON_GETAUTHENTICATOR_DOUBLE_POINTER */
-+out_free_rep:
-+ krb5_free_data_contents(krb5_ctx->context, &ap_rep);
-+out_free_key:
-+ krb5_free_keyblock(krb5_ctx->context, session_key);
-+out_free_con_auth:
-+ krb5_free_ticket(krb5_ctx->context, ticket);
-+ krb5_auth_con_free(krb5_ctx->context, auth_context);
-+ return retval;
-+}
-+
-+static int setup_krb5_ctx(struct spnego_mech_ctx *mech_ctx)
-+{
-+ struct spnego_krb5_ctx *krb5_ctx;
-+ krb5_error_code krb_retval;
-+
-+ krb5_ctx = g_try_malloc0(sizeof(*krb5_ctx));
-+ if (!krb5_ctx)
-+ return -ENOMEM;
-+
-+ krb_retval = krb5_init_context(&krb5_ctx->context);
-+ if (krb_retval) {
-+ g_free(krb5_ctx);
-+ pr_err("while initializing krb5 context\n");
-+ return -EINVAL;
-+ }
-+
-+ krb_retval = acquire_creds_from_keytab(krb5_ctx->context,
-+ mech_ctx->params.krb5.service_name,
-+ mech_ctx->params.krb5.keytab_name,
-+ &krb5_ctx->creds, &krb5_ctx->keytab);
-+ if (krb_retval) {
-+ krb5_free_context(krb5_ctx->context);
-+ g_free(krb5_ctx);
-+ return -EINVAL;
-+ }
-+
-+ mech_ctx->private = krb5_ctx;
-+ return 0;
-+}
-+
-+static int setup_krb5(struct spnego_mech_ctx *mech_ctx)
-+{
-+ mech_ctx->oid = KRB5_OID;
-+ mech_ctx->oid_len = ARRAY_SIZE(KRB5_OID);
-+ return setup_krb5_ctx(mech_ctx);
-+}
-+
-+static int setup_mskrb5(struct spnego_mech_ctx *mech_ctx)
-+{
-+ mech_ctx->oid = MSKRB5_OID;
-+ mech_ctx->oid_len = ARRAY_SIZE(MSKRB5_OID);
-+ return setup_krb5_ctx(mech_ctx);
-+}
-+
-+static void cleanup_krb5(struct spnego_mech_ctx *mech_ctx)
-+{
-+ if (mech_ctx->private) {
-+ struct spnego_krb5_ctx *krb5_ctx;
-+
-+ krb5_ctx = (struct spnego_krb5_ctx *)mech_ctx->private;
-+ krb5_free_cred_contents(krb5_ctx->context, &krb5_ctx->creds);
-+ krb5_kt_close(krb5_ctx->context, krb5_ctx->keytab);
-+ krb5_free_context(krb5_ctx->context);
-+ g_free(krb5_ctx);
-+ mech_ctx->private = NULL;
-+ }
-+ if (mech_ctx->params.krb5.service_name)
-+ free(mech_ctx->params.krb5.service_name);
-+ if (mech_ctx->params.krb5.keytab_name)
-+ free(mech_ctx->params.krb5.keytab_name);
-+}
-+
-+struct spnego_mech_operations spnego_krb5_operations = {
-+ .setup = setup_krb5,
-+ .cleanup = cleanup_krb5,
-+ .handle_authen = handle_krb5_authen,
-+};
-+
-+struct spnego_mech_operations spnego_mskrb5_operations = {
-+ .setup = setup_mskrb5,
-+ .cleanup = cleanup_krb5,
-+ .handle_authen = handle_krb5_authen,
-+};
---- a/lib/management/tree_conn.c
-+++ /dev/null
-@@ -1,231 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0-or-later
--/*
-- * Copyright (C) 2018 Samsung Electronics Co., Ltd.
-- *
-- * linux-cifsd-devel@lists.sourceforge.net
-- */
--
--#include <stdlib.h>
--#include <string.h>
--#include <glib.h>
--
--#include "linux/ksmbd_server.h"
--#include "management/tree_conn.h"
--#include "management/session.h"
--#include "management/share.h"
--#include "management/user.h"
--#include "ksmbdtools.h"
--
--static struct ksmbd_tree_conn *new_ksmbd_tree_conn(void)
--{
-- struct ksmbd_tree_conn *conn;
--
-- conn = g_try_malloc0(sizeof(struct ksmbd_tree_conn));
-- if (!conn)
-- return NULL;
--
-- conn->id = 0;
-- return conn;
--}
--
--void tcm_tree_conn_free(struct ksmbd_tree_conn *conn)
--{
-- shm_close_connection(conn->share);
-- put_ksmbd_share(conn->share);
-- g_free(conn);
--}
--
--int tcm_handle_tree_connect(struct ksmbd_tree_connect_request *req,
-- struct ksmbd_tree_connect_response *resp)
--{
-- struct ksmbd_user *user = NULL;
-- struct ksmbd_share *share = NULL;
-- struct ksmbd_tree_conn *conn = new_ksmbd_tree_conn();
-- int ret;
--
-- if (!conn) {
-- resp->status = KSMBD_TREE_CONN_STATUS_NOMEM;
-- return -ENOMEM;
-- }
--
-- if (sm_check_sessions_capacity(req->session_id)) {
-- resp->status = KSMBD_TREE_CONN_STATUS_TOO_MANY_SESSIONS;
-- pr_debug("treecon: Too many active sessions\n");
-- goto out_error;
-- }
--
-- if (global_conf.map_to_guest == KSMBD_CONF_MAP_TO_GUEST_NEVER) {
-- if (req->account_flags & KSMBD_USER_FLAG_BAD_PASSWORD) {
-- resp->status = KSMBD_TREE_CONN_STATUS_INVALID_USER;
-- pr_debug("treecon: Bad user password\n");
-- goto out_error;
-- }
-- }
--
-- share = shm_lookup_share(req->share);
-- if (!share) {
-- resp->status = KSMBD_TREE_CONN_STATUS_NO_SHARE;
-- pr_err("treecon: Unknown net share: %s\n", req->share);
-- goto out_error;
-- }
--
-- if (test_share_flag(share, KSMBD_SHARE_FLAG_WRITEABLE))
-- set_conn_flag(conn, KSMBD_TREE_CONN_FLAG_WRITABLE);
-- if (test_share_flag(share, KSMBD_SHARE_FLAG_READONLY))
-- set_conn_flag(conn, KSMBD_TREE_CONN_FLAG_READ_ONLY);
-- if (test_share_flag(share, KSMBD_SHARE_FLAG_UPDATE))
-- set_conn_flag(conn, KSMBD_TREE_CONN_FLAG_UPDATE);
--
-- if (shm_open_connection(share)) {
-- resp->status = KSMBD_TREE_CONN_STATUS_TOO_MANY_CONNS;
-- pr_debug("treecon: Too many connections to net share\n");
-- goto out_error;
-- }
--
-- ret = shm_lookup_hosts_map(share,
-- KSMBD_SHARE_HOSTS_ALLOW_MAP,
-- req->peer_addr);
-- if (ret == -ENOENT) {
-- resp->status = KSMBD_TREE_CONN_STATUS_HOST_DENIED;
-- pr_debug("treecon: Host denied: %s\n", req->peer_addr);
-- goto out_error;
-- }
--
-- if (ret != 0) {
-- ret = shm_lookup_hosts_map(share,
-- KSMBD_SHARE_HOSTS_DENY_MAP,
-- req->peer_addr);
-- if (ret == 0) {
-- resp->status = KSMBD_TREE_CONN_STATUS_HOST_DENIED;
-- pr_err("treecon: Host denied: %s\n", req->peer_addr);
-- goto out_error;
-- }
-- }
--
-- if (global_conf.restrict_anon >= KSMBD_RESTRICT_ANON_TYPE_1) {
-- int deny;
--
-- deny = !test_share_flag(share, KSMBD_SHARE_FLAG_GUEST_OK);
-- deny |= test_share_flag(share, KSMBD_SHARE_FLAG_PIPE);
--
-- if (req->account_flags & KSMBD_USER_FLAG_GUEST_ACCOUNT &&
-- deny) {
-- pr_debug("treecon: Deny, restricted session\n");
-- resp->status = KSMBD_TREE_CONN_STATUS_ERROR;
-- goto out_error;
-- }
-- }
--
-- if ((req->account_flags & KSMBD_USER_FLAG_GUEST_ACCOUNT) &&
-- !test_share_flag(share, KSMBD_SHARE_FLAG_PIPE) &&
-- !test_share_flag(share, KSMBD_SHARE_FLAG_GUEST_OK)) {
-- pr_debug("treecon: Deny, guest not allowed\n");
-- resp->status = KSMBD_TREE_CONN_STATUS_ERROR;
-- goto out_error;
-- }
--
-- if ((req->account_flags & KSMBD_USER_FLAG_GUEST_ACCOUNT) &&
-- test_share_flag(share, KSMBD_SHARE_FLAG_GUEST_OK)) {
-- pr_debug("treecon: Net share permits guest login\n");
-- user = usm_lookup_user(share->guest_account);
-- if (user) {
-- set_conn_flag(conn, KSMBD_TREE_CONN_FLAG_GUEST_ACCOUNT);
-- goto bind;
-- }
--
-- user = usm_lookup_user(global_conf.guest_account);
-- if (user) {
-- set_conn_flag(conn, KSMBD_TREE_CONN_FLAG_GUEST_ACCOUNT);
-- goto bind;
-- }
-- }
--
-- user = usm_lookup_user(req->account);
-- if (!user) {
-- resp->status = KSMBD_TREE_CONN_STATUS_NO_USER;
-- pr_err("treecon: User `%s' not found\n", req->account);
-- goto out_error;
-- }
--
-- user->failed_login_count = 0;
-- user->flags &= ~KSMBD_USER_FLAG_DELAY_SESSION;
--
-- if (test_user_flag(user, KSMBD_USER_FLAG_GUEST_ACCOUNT))
-- set_conn_flag(conn, KSMBD_TREE_CONN_FLAG_GUEST_ACCOUNT);
--
-- ret = shm_lookup_users_map(share,
-- KSMBD_SHARE_ADMIN_USERS_MAP,
-- req->account);
-- if (ret == 0) {
-- set_conn_flag(conn, KSMBD_TREE_CONN_FLAG_ADMIN_ACCOUNT);
-- goto bind;
-- }
--
-- ret = shm_lookup_users_map(share,
-- KSMBD_SHARE_INVALID_USERS_MAP,
-- req->account);
-- if (ret == 0) {
-- resp->status = KSMBD_TREE_CONN_STATUS_INVALID_USER;
-- pr_err("treecon: User is on invalid users list\n");
-- goto out_error;
-- }
--
-- ret = shm_lookup_users_map(share,
-- KSMBD_SHARE_READ_LIST_MAP,
-- req->account);
-- if (ret == 0) {
-- set_conn_flag(conn, KSMBD_TREE_CONN_FLAG_READ_ONLY);
-- clear_conn_flag(conn, KSMBD_TREE_CONN_FLAG_WRITABLE);
-- goto bind;
-- }
--
-- ret = shm_lookup_users_map(share,
-- KSMBD_SHARE_WRITE_LIST_MAP,
-- req->account);
-- if (ret == 0) {
-- set_conn_flag(conn, KSMBD_TREE_CONN_FLAG_WRITABLE);
-- goto bind;
-- }
--
-- ret = shm_lookup_users_map(share,
-- KSMBD_SHARE_VALID_USERS_MAP,
-- req->account);
-- if (ret == 0)
-- goto bind;
-- if (ret == -ENOENT) {
-- resp->status = KSMBD_TREE_CONN_STATUS_INVALID_USER;
-- pr_err("treecon: User is not on valid users list\n");
-- goto out_error;
-- }
--
--bind:
-- conn->id = req->connect_id;
-- conn->share = share;
-- resp->status = KSMBD_TREE_CONN_STATUS_OK;
-- resp->connection_flags = conn->flags;
--
-- if (sm_handle_tree_connect(req->session_id, user, conn)) {
-- pr_err("treecon: Unable to bind tree connection\n");
-- tcm_tree_conn_free(conn);
-- put_ksmbd_user(user);
-- }
--
-- g_rw_lock_writer_lock(&share->update_lock);
-- clear_share_flag(share, KSMBD_SHARE_FLAG_UPDATE);
-- g_rw_lock_writer_unlock(&share->update_lock);
--
-- return 0;
--out_error:
-- tcm_tree_conn_free(conn);
-- shm_close_connection(share);
-- put_ksmbd_share(share);
-- put_ksmbd_user(user);
-- return -EINVAL;
--}
--
--int tcm_handle_tree_disconnect(unsigned long long sess_id,
-- unsigned long long tree_conn_id)
--{
-- sm_handle_tree_disconnect(sess_id, tree_conn_id);
-- return 0;
--}
---- /dev/null
-+++ b/tools/management/tree_conn.c
-@@ -0,0 +1,231 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+/*
-+ * Copyright (C) 2018 Samsung Electronics Co., Ltd.
-+ *
-+ * linux-cifsd-devel@lists.sourceforge.net
-+ */
-+
-+#include <stdlib.h>
-+#include <string.h>
-+#include <glib.h>
-+
-+#include "linux/ksmbd_server.h"
-+#include "management/tree_conn.h"
-+#include "management/session.h"
-+#include "management/share.h"
-+#include "management/user.h"
-+#include "tools.h"
-+
-+static struct ksmbd_tree_conn *new_ksmbd_tree_conn(void)
-+{
-+ struct ksmbd_tree_conn *conn;
-+
-+ conn = g_try_malloc0(sizeof(struct ksmbd_tree_conn));
-+ if (!conn)
-+ return NULL;
-+
-+ conn->id = 0;
-+ return conn;
-+}
-+
-+void tcm_tree_conn_free(struct ksmbd_tree_conn *conn)
-+{
-+ shm_close_connection(conn->share);
-+ put_ksmbd_share(conn->share);
-+ g_free(conn);
-+}
-+
-+int tcm_handle_tree_connect(struct ksmbd_tree_connect_request *req,
-+ struct ksmbd_tree_connect_response *resp)
-+{
-+ struct ksmbd_user *user = NULL;
-+ struct ksmbd_share *share = NULL;
-+ struct ksmbd_tree_conn *conn = new_ksmbd_tree_conn();
-+ int ret;
-+
-+ if (!conn) {
-+ resp->status = KSMBD_TREE_CONN_STATUS_NOMEM;
-+ return -ENOMEM;
-+ }
-+
-+ if (sm_check_sessions_capacity(req->session_id)) {
-+ resp->status = KSMBD_TREE_CONN_STATUS_TOO_MANY_SESSIONS;
-+ pr_debug("treecon: Too many active sessions\n");
-+ goto out_error;
-+ }
-+
-+ if (global_conf.map_to_guest == KSMBD_CONF_MAP_TO_GUEST_NEVER) {
-+ if (req->account_flags & KSMBD_USER_FLAG_BAD_PASSWORD) {
-+ resp->status = KSMBD_TREE_CONN_STATUS_INVALID_USER;
-+ pr_debug("treecon: Bad user password\n");
-+ goto out_error;
-+ }
-+ }
-+
-+ share = shm_lookup_share(req->share);
-+ if (!share) {
-+ resp->status = KSMBD_TREE_CONN_STATUS_NO_SHARE;
-+ pr_err("treecon: Unknown net share: %s\n", req->share);
-+ goto out_error;
-+ }
-+
-+ if (test_share_flag(share, KSMBD_SHARE_FLAG_WRITEABLE))
-+ set_conn_flag(conn, KSMBD_TREE_CONN_FLAG_WRITABLE);
-+ if (test_share_flag(share, KSMBD_SHARE_FLAG_READONLY))
-+ set_conn_flag(conn, KSMBD_TREE_CONN_FLAG_READ_ONLY);
-+ if (test_share_flag(share, KSMBD_SHARE_FLAG_UPDATE))
-+ set_conn_flag(conn, KSMBD_TREE_CONN_FLAG_UPDATE);
-+
-+ if (shm_open_connection(share)) {
-+ resp->status = KSMBD_TREE_CONN_STATUS_TOO_MANY_CONNS;
-+ pr_debug("treecon: Too many connections to net share\n");
-+ goto out_error;
-+ }
-+
-+ ret = shm_lookup_hosts_map(share,
-+ KSMBD_SHARE_HOSTS_ALLOW_MAP,
-+ req->peer_addr);
-+ if (ret == -ENOENT) {
-+ resp->status = KSMBD_TREE_CONN_STATUS_HOST_DENIED;
-+ pr_debug("treecon: Host denied: %s\n", req->peer_addr);
-+ goto out_error;
-+ }
-+
-+ if (ret != 0) {
-+ ret = shm_lookup_hosts_map(share,
-+ KSMBD_SHARE_HOSTS_DENY_MAP,
-+ req->peer_addr);
-+ if (ret == 0) {
-+ resp->status = KSMBD_TREE_CONN_STATUS_HOST_DENIED;
-+ pr_err("treecon: Host denied: %s\n", req->peer_addr);
-+ goto out_error;
-+ }
-+ }
-+
-+ if (global_conf.restrict_anon >= KSMBD_RESTRICT_ANON_TYPE_1) {
-+ int deny;
-+
-+ deny = !test_share_flag(share, KSMBD_SHARE_FLAG_GUEST_OK);
-+ deny |= test_share_flag(share, KSMBD_SHARE_FLAG_PIPE);
-+
-+ if (req->account_flags & KSMBD_USER_FLAG_GUEST_ACCOUNT &&
-+ deny) {
-+ pr_debug("treecon: Deny, restricted session\n");
-+ resp->status = KSMBD_TREE_CONN_STATUS_ERROR;
-+ goto out_error;
-+ }
-+ }
-+
-+ if ((req->account_flags & KSMBD_USER_FLAG_GUEST_ACCOUNT) &&
-+ !test_share_flag(share, KSMBD_SHARE_FLAG_PIPE) &&
-+ !test_share_flag(share, KSMBD_SHARE_FLAG_GUEST_OK)) {
-+ pr_debug("treecon: Deny, guest not allowed\n");
-+ resp->status = KSMBD_TREE_CONN_STATUS_ERROR;
-+ goto out_error;
-+ }
-+
-+ if ((req->account_flags & KSMBD_USER_FLAG_GUEST_ACCOUNT) &&
-+ test_share_flag(share, KSMBD_SHARE_FLAG_GUEST_OK)) {
-+ pr_debug("treecon: Net share permits guest login\n");
-+ user = usm_lookup_user(share->guest_account);
-+ if (user) {
-+ set_conn_flag(conn, KSMBD_TREE_CONN_FLAG_GUEST_ACCOUNT);
-+ goto bind;
-+ }
-+
-+ user = usm_lookup_user(global_conf.guest_account);
-+ if (user) {
-+ set_conn_flag(conn, KSMBD_TREE_CONN_FLAG_GUEST_ACCOUNT);
-+ goto bind;
-+ }
-+ }
-+
-+ user = usm_lookup_user(req->account);
-+ if (!user) {
-+ resp->status = KSMBD_TREE_CONN_STATUS_NO_USER;
-+ pr_err("treecon: User `%s' not found\n", req->account);
-+ goto out_error;
-+ }
-+
-+ user->failed_login_count = 0;
-+ user->flags &= ~KSMBD_USER_FLAG_DELAY_SESSION;
-+
-+ if (test_user_flag(user, KSMBD_USER_FLAG_GUEST_ACCOUNT))
-+ set_conn_flag(conn, KSMBD_TREE_CONN_FLAG_GUEST_ACCOUNT);
-+
-+ ret = shm_lookup_users_map(share,
-+ KSMBD_SHARE_ADMIN_USERS_MAP,
-+ req->account);
-+ if (ret == 0) {
-+ set_conn_flag(conn, KSMBD_TREE_CONN_FLAG_ADMIN_ACCOUNT);
-+ goto bind;
-+ }
-+
-+ ret = shm_lookup_users_map(share,
-+ KSMBD_SHARE_INVALID_USERS_MAP,
-+ req->account);
-+ if (ret == 0) {
-+ resp->status = KSMBD_TREE_CONN_STATUS_INVALID_USER;
-+ pr_err("treecon: User is on invalid users list\n");
-+ goto out_error;
-+ }
-+
-+ ret = shm_lookup_users_map(share,
-+ KSMBD_SHARE_READ_LIST_MAP,
-+ req->account);
-+ if (ret == 0) {
-+ set_conn_flag(conn, KSMBD_TREE_CONN_FLAG_READ_ONLY);
-+ clear_conn_flag(conn, KSMBD_TREE_CONN_FLAG_WRITABLE);
-+ goto bind;
-+ }
-+
-+ ret = shm_lookup_users_map(share,
-+ KSMBD_SHARE_WRITE_LIST_MAP,
-+ req->account);
-+ if (ret == 0) {
-+ set_conn_flag(conn, KSMBD_TREE_CONN_FLAG_WRITABLE);
-+ goto bind;
-+ }
-+
-+ ret = shm_lookup_users_map(share,
-+ KSMBD_SHARE_VALID_USERS_MAP,
-+ req->account);
-+ if (ret == 0)
-+ goto bind;
-+ if (ret == -ENOENT) {
-+ resp->status = KSMBD_TREE_CONN_STATUS_INVALID_USER;
-+ pr_err("treecon: User is not on valid users list\n");
-+ goto out_error;
-+ }
-+
-+bind:
-+ conn->id = req->connect_id;
-+ conn->share = share;
-+ resp->status = KSMBD_TREE_CONN_STATUS_OK;
-+ resp->connection_flags = conn->flags;
-+
-+ if (sm_handle_tree_connect(req->session_id, user, conn)) {
-+ pr_err("treecon: Unable to bind tree connection\n");
-+ tcm_tree_conn_free(conn);
-+ put_ksmbd_user(user);
-+ }
-+
-+ g_rw_lock_writer_lock(&share->update_lock);
-+ clear_share_flag(share, KSMBD_SHARE_FLAG_UPDATE);
-+ g_rw_lock_writer_unlock(&share->update_lock);
-+
-+ return 0;
-+out_error:
-+ tcm_tree_conn_free(conn);
-+ shm_close_connection(share);
-+ put_ksmbd_share(share);
-+ put_ksmbd_user(user);
-+ return -EINVAL;
-+}
-+
-+int tcm_handle_tree_disconnect(unsigned long long sess_id,
-+ unsigned long long tree_conn_id)
-+{
-+ sm_handle_tree_disconnect(sess_id, tree_conn_id);
-+ return 0;
-+}
---- a/lib/management/user.c
-+++ /dev/null
-@@ -1,412 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0-or-later
--/*
-- * Copyright (C) 2018 Samsung Electronics Co., Ltd.
-- *
-- * linux-cifsd-devel@lists.sourceforge.net
-- */
--
--#include <stdlib.h>
--#include <string.h>
--#include <glib.h>
--
--#include "linux/ksmbd_server.h"
--#include "management/user.h"
--#include "ksmbdtools.h"
--
--#define KSMBD_USER_STATE_FREEING 1
--
--static GHashTable *users_table;
--static GRWLock users_table_lock;
--
--static void kill_ksmbd_user(struct ksmbd_user *user)
--{
-- pr_debug("Kill user `%s'\n", user->name);
--
-- free(user->name);
-- free(user->pass_b64);
-- free(user->pass);
-- g_rw_lock_clear(&user->update_lock);
-- g_free(user);
--}
--
--static int __usm_remove_user(struct ksmbd_user *user)
--{
-- int ret = 0;
--
-- if (user->state != KSMBD_USER_STATE_FREEING) {
-- g_rw_lock_writer_lock(&users_table_lock);
-- if (!g_hash_table_remove(users_table, user->name))
-- ret = -EINVAL;
-- g_rw_lock_writer_unlock(&users_table_lock);
-- }
-- if (!ret)
-- kill_ksmbd_user(user);
-- return ret;
--}
--
--struct ksmbd_user *get_ksmbd_user(struct ksmbd_user *user)
--{
-- g_rw_lock_writer_lock(&user->update_lock);
-- if (user->ref_count != 0) {
-- user->ref_count++;
-- g_rw_lock_writer_unlock(&user->update_lock);
-- } else {
-- g_rw_lock_writer_unlock(&user->update_lock);
-- user = NULL;
-- }
-- return user;
--}
--
--void put_ksmbd_user(struct ksmbd_user *user)
--{
-- int drop;
--
-- if (!user)
-- return;
--
-- g_rw_lock_writer_lock(&user->update_lock);
-- user->ref_count--;
-- drop = !user->ref_count;
-- g_rw_lock_writer_unlock(&user->update_lock);
--
-- if (!drop)
-- return;
--
-- __usm_remove_user(user);
--}
--
--static gboolean put_user_callback(gpointer _k, gpointer _v, gpointer data)
--{
-- struct ksmbd_user *user = (struct ksmbd_user *)_v;
--
-- user->state = KSMBD_USER_STATE_FREEING;
-- put_ksmbd_user(user);
-- return TRUE;
--}
--
--void usm_remove_all_users(void)
--{
-- g_rw_lock_writer_lock(&users_table_lock);
-- g_hash_table_foreach_remove(users_table, put_user_callback, NULL);
-- g_rw_lock_writer_unlock(&users_table_lock);
--}
--
--static struct ksmbd_user *new_ksmbd_user(char *name, char *pwd)
--{
-- struct ksmbd_user *user;
-- struct passwd *passwd;
-- size_t pass_sz;
--
-- user = g_try_malloc0(sizeof(struct ksmbd_user));
-- if (!user)
-- return NULL;
--
-- g_rw_lock_init(&user->update_lock);
-- user->name = name;
-- user->pass_b64 = pwd;
-- user->ref_count = 1;
-- user->gid = 9999;
-- user->uid = 9999;
-- passwd = getpwnam(name);
-- if (passwd) {
-- user->uid = passwd->pw_uid;
-- user->gid = passwd->pw_gid;
-- }
--
-- user->pass = base64_decode(user->pass_b64, &pass_sz);
-- user->pass_sz = (int)pass_sz;
-- return user;
--}
--
--static void free_hash_entry(gpointer k, gpointer u, gpointer user_data)
--{
-- kill_ksmbd_user(u);
--}
--
--static void usm_clear_users(void)
--{
-- g_hash_table_foreach(users_table, free_hash_entry, NULL);
--}
--
--void usm_destroy(void)
--{
-- if (users_table) {
-- usm_clear_users();
-- g_hash_table_destroy(users_table);
-- }
-- g_rw_lock_clear(&users_table_lock);
--}
--
--int usm_init(void)
--{
-- users_table = g_hash_table_new(g_str_hash, g_str_equal);
-- if (!users_table)
-- return -ENOMEM;
-- g_rw_lock_init(&users_table_lock);
-- return 0;
--}
--
--static struct ksmbd_user *__usm_lookup_user(char *name)
--{
-- return g_hash_table_lookup(users_table, name);
--}
--
--struct ksmbd_user *usm_lookup_user(char *name)
--{
-- struct ksmbd_user *user, *ret;
--
-- if (!name)
-- return NULL;
--
-- g_rw_lock_reader_lock(&users_table_lock);
-- user = __usm_lookup_user(name);
-- if (user) {
-- ret = get_ksmbd_user(user);
-- if (!ret)
-- user = NULL;
-- }
-- g_rw_lock_reader_unlock(&users_table_lock);
-- return user;
--}
--
--int usm_add_new_user(char *name, char *pwd)
--{
-- int ret = 0;
-- struct ksmbd_user *user = new_ksmbd_user(name, pwd);
--
-- if (!user) {
-- free(name);
-- free(pwd);
-- return -ENOMEM;
-- }
--
-- g_rw_lock_writer_lock(&users_table_lock);
-- if (__usm_lookup_user(name)) {
-- g_rw_lock_writer_unlock(&users_table_lock);
-- pr_info("User `%s' already exists\n", name);
-- kill_ksmbd_user(user);
-- return 0;
-- }
--
-- pr_debug("New user `%s'\n", user->name);
-- if (!g_hash_table_insert(users_table, user->name, user)) {
-- kill_ksmbd_user(user);
-- ret = -EINVAL;
-- }
-- g_rw_lock_writer_unlock(&users_table_lock);
-- return ret;
--}
--
--int usm_add_update_user_from_pwdentry(char *data)
--{
-- struct ksmbd_user *user;
-- char *name;
-- char *pwd;
-- char *pos = strchr(data, ':');
-- int ret;
--
-- if (!pos) {
-- pr_err("Invalid pwd entry: %s\n", data);
-- return -EINVAL;
-- }
--
-- *pos = 0x00;
-- name = g_strdup(data);
-- pwd = g_strdup(pos + 1);
--
-- if (!name || !pwd) {
-- free(name);
-- free(pwd);
-- return -ENOMEM;
-- }
--
-- user = usm_lookup_user(name);
-- if (user) {
-- ret = usm_update_user_password(user, pwd);
-- put_ksmbd_user(user);
--
-- free(name);
-- free(pwd);
-- return ret;
-- }
-- return usm_add_new_user(name, pwd);
--}
--
--int usm_add_subauth_global_conf(char *data)
--{
-- char *pos = data;
-- char *spos;
--
-- if (!pos)
-- return -EINVAL;
--
-- spos = strchr(pos, ':');
-- if (!spos) {
-- pr_err("Invalid subauth entry: %s\n", data);
-- return -EINVAL;
-- }
--
-- *spos = 0x00;
-- global_conf.gen_subauth[0] = atoi(pos);
-- pos = spos + 1;
--
-- spos = strchr(pos, ':');
-- if (!spos) {
-- pr_err("Invalid subauth entry: %s\n", data);
-- return -EINVAL;
-- }
-- *spos = 0x00;
-- global_conf.gen_subauth[1] = atoi(pos);
-- global_conf.gen_subauth[2] = atoi(spos + 1);
--
-- return 0;
--}
--
--void for_each_ksmbd_user(walk_users cb, gpointer user_data)
--{
-- g_rw_lock_reader_lock(&users_table_lock);
-- g_hash_table_foreach(users_table, cb, user_data);
-- g_rw_lock_reader_unlock(&users_table_lock);
--}
--
--int usm_update_user_password(struct ksmbd_user *user, char *pswd)
--{
-- size_t pass_sz;
-- char *pass_b64 = g_strdup(pswd);
-- char *pass = base64_decode(pass_b64, &pass_sz);
--
-- if (!pass_b64 || !pass) {
-- free(pass_b64);
-- free(pass);
-- pr_err("Out of memory\n");
-- return -ENOMEM;
-- }
--
-- pr_debug("Update user password: %s\n", user->name);
-- g_rw_lock_writer_lock(&user->update_lock);
-- free(user->pass_b64);
-- free(user->pass);
-- user->pass_b64 = pass_b64;
-- user->pass = pass;
-- user->pass_sz = (int)pass_sz;
-- g_rw_lock_writer_unlock(&user->update_lock);
--
-- return 0;
--}
--
--static int usm_copy_user_passhash(struct ksmbd_user *user,
-- char *pass,
-- size_t sz)
--{
-- int ret = -ENOSPC;
--
-- if (test_user_flag(user, KSMBD_USER_FLAG_GUEST_ACCOUNT))
-- return 0;
--
-- g_rw_lock_reader_lock(&user->update_lock);
-- if (sz >= user->pass_sz) {
-- memcpy(pass, user->pass, user->pass_sz);
-- ret = user->pass_sz;
-- }
-- g_rw_lock_reader_unlock(&user->update_lock);
--
-- return ret;
--}
--
--static int usm_copy_user_account(struct ksmbd_user *user,
-- char *account,
-- size_t sz)
--{
-- int account_sz;
--
-- if (test_user_flag(user, KSMBD_USER_FLAG_GUEST_ACCOUNT))
-- return 0;
--
-- account_sz = strlen(user->name);
-- if (sz >= account_sz) {
-- memcpy(account, user->name, account_sz);
-- return 0;
-- }
-- pr_err("Cannot copy user data, buffer overrun\n");
-- return -ENOSPC;
--}
--
--static void __handle_login_request(struct ksmbd_login_response *resp,
-- struct ksmbd_user *user)
--{
-- int hash_sz;
--
-- resp->gid = user->gid;
-- resp->uid = user->uid;
-- resp->status = user->flags;
-- resp->status |= KSMBD_USER_FLAG_OK;
--
-- hash_sz = usm_copy_user_passhash(user,
-- resp->hash,
-- sizeof(resp->hash));
-- if (hash_sz < 0) {
-- resp->status = KSMBD_USER_FLAG_INVALID;
-- } else {
-- resp->hash_sz = (unsigned short)hash_sz;
-- if (usm_copy_user_account(user,
-- resp->account,
-- sizeof(resp->account)))
-- resp->status = KSMBD_USER_FLAG_INVALID;
-- }
--}
--
--int usm_handle_login_request(struct ksmbd_login_request *req,
-- struct ksmbd_login_response *resp)
--{
-- struct ksmbd_user *user = NULL;
-- int null_session = 0;
--
-- if (req->account[0] == '\0')
-- null_session = 1;
--
-- if (!null_session)
-- user = usm_lookup_user(req->account);
-- if (user) {
-- __handle_login_request(resp, user);
-- put_ksmbd_user(user);
-- return 0;
-- }
--
-- resp->status = KSMBD_USER_FLAG_BAD_USER;
-- if (!null_session &&
-- global_conf.map_to_guest == KSMBD_CONF_MAP_TO_GUEST_NEVER)
-- return 0;
--
-- if (null_session ||
-- global_conf.map_to_guest == KSMBD_CONF_MAP_TO_GUEST_BAD_USER)
-- user = usm_lookup_user(global_conf.guest_account);
--
-- if (!user)
-- return 0;
--
-- __handle_login_request(resp, user);
-- put_ksmbd_user(user);
-- return 0;
--}
--
--int usm_handle_logout_request(struct ksmbd_logout_request *req)
--{
-- struct ksmbd_user *user;
--
-- user = usm_lookup_user(req->account);
-- if (!user)
-- return -ENOENT;
--
-- if (req->account_flags & KSMBD_USER_FLAG_BAD_PASSWORD) {
-- if (user->failed_login_count < 10)
-- user->failed_login_count++;
-- else
-- user->flags |= KSMBD_USER_FLAG_DELAY_SESSION;
-- } else {
-- user->failed_login_count = 0;
-- user->flags &= ~KSMBD_USER_FLAG_DELAY_SESSION;
-- }
--
-- put_ksmbd_user(user);
-- return 0;
--}
---- /dev/null
-+++ b/tools/management/user.c
-@@ -0,0 +1,412 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+/*
-+ * Copyright (C) 2018 Samsung Electronics Co., Ltd.
-+ *
-+ * linux-cifsd-devel@lists.sourceforge.net
-+ */
-+
-+#include <stdlib.h>
-+#include <string.h>
-+#include <glib.h>
-+
-+#include "linux/ksmbd_server.h"
-+#include "management/user.h"
-+#include "tools.h"
-+
-+#define KSMBD_USER_STATE_FREEING 1
-+
-+static GHashTable *users_table;
-+static GRWLock users_table_lock;
-+
-+static void kill_ksmbd_user(struct ksmbd_user *user)
-+{
-+ pr_debug("Kill user `%s'\n", user->name);
-+
-+ free(user->name);
-+ free(user->pass_b64);
-+ free(user->pass);
-+ g_rw_lock_clear(&user->update_lock);
-+ g_free(user);
-+}
-+
-+static int __usm_remove_user(struct ksmbd_user *user)
-+{
-+ int ret = 0;
-+
-+ if (user->state != KSMBD_USER_STATE_FREEING) {
-+ g_rw_lock_writer_lock(&users_table_lock);
-+ if (!g_hash_table_remove(users_table, user->name))
-+ ret = -EINVAL;
-+ g_rw_lock_writer_unlock(&users_table_lock);
-+ }
-+ if (!ret)
-+ kill_ksmbd_user(user);
-+ return ret;
-+}
-+
-+struct ksmbd_user *get_ksmbd_user(struct ksmbd_user *user)
-+{
-+ g_rw_lock_writer_lock(&user->update_lock);
-+ if (user->ref_count != 0) {
-+ user->ref_count++;
-+ g_rw_lock_writer_unlock(&user->update_lock);
-+ } else {
-+ g_rw_lock_writer_unlock(&user->update_lock);
-+ user = NULL;
-+ }
-+ return user;
-+}
-+
-+void put_ksmbd_user(struct ksmbd_user *user)
-+{
-+ int drop;
-+
-+ if (!user)
-+ return;
-+
-+ g_rw_lock_writer_lock(&user->update_lock);
-+ user->ref_count--;
-+ drop = !user->ref_count;
-+ g_rw_lock_writer_unlock(&user->update_lock);
-+
-+ if (!drop)
-+ return;
-+
-+ __usm_remove_user(user);
-+}
-+
-+static gboolean put_user_callback(gpointer _k, gpointer _v, gpointer data)
-+{
-+ struct ksmbd_user *user = (struct ksmbd_user *)_v;
-+
-+ user->state = KSMBD_USER_STATE_FREEING;
-+ put_ksmbd_user(user);
-+ return TRUE;
-+}
-+
-+void usm_remove_all_users(void)
-+{
-+ g_rw_lock_writer_lock(&users_table_lock);
-+ g_hash_table_foreach_remove(users_table, put_user_callback, NULL);
-+ g_rw_lock_writer_unlock(&users_table_lock);
-+}
-+
-+static struct ksmbd_user *new_ksmbd_user(char *name, char *pwd)
-+{
-+ struct ksmbd_user *user;
-+ struct passwd *passwd;
-+ size_t pass_sz;
-+
-+ user = g_try_malloc0(sizeof(struct ksmbd_user));
-+ if (!user)
-+ return NULL;
-+
-+ g_rw_lock_init(&user->update_lock);
-+ user->name = name;
-+ user->pass_b64 = pwd;
-+ user->ref_count = 1;
-+ user->gid = 9999;
-+ user->uid = 9999;
-+ passwd = getpwnam(name);
-+ if (passwd) {
-+ user->uid = passwd->pw_uid;
-+ user->gid = passwd->pw_gid;
-+ }
-+
-+ user->pass = base64_decode(user->pass_b64, &pass_sz);
-+ user->pass_sz = (int)pass_sz;
-+ return user;
-+}
-+
-+static void free_hash_entry(gpointer k, gpointer u, gpointer user_data)
-+{
-+ kill_ksmbd_user(u);
-+}
-+
-+static void usm_clear_users(void)
-+{
-+ g_hash_table_foreach(users_table, free_hash_entry, NULL);
-+}
-+
-+void usm_destroy(void)
-+{
-+ if (users_table) {
-+ usm_clear_users();
-+ g_hash_table_destroy(users_table);
-+ }
-+ g_rw_lock_clear(&users_table_lock);
-+}
-+
-+int usm_init(void)
-+{
-+ users_table = g_hash_table_new(g_str_hash, g_str_equal);
-+ if (!users_table)
-+ return -ENOMEM;
-+ g_rw_lock_init(&users_table_lock);
-+ return 0;
-+}
-+
-+static struct ksmbd_user *__usm_lookup_user(char *name)
-+{
-+ return g_hash_table_lookup(users_table, name);
-+}
-+
-+struct ksmbd_user *usm_lookup_user(char *name)
-+{
-+ struct ksmbd_user *user, *ret;
-+
-+ if (!name)
-+ return NULL;
-+
-+ g_rw_lock_reader_lock(&users_table_lock);
-+ user = __usm_lookup_user(name);
-+ if (user) {
-+ ret = get_ksmbd_user(user);
-+ if (!ret)
-+ user = NULL;
-+ }
-+ g_rw_lock_reader_unlock(&users_table_lock);
-+ return user;
-+}
-+
-+int usm_add_new_user(char *name, char *pwd)
-+{
-+ int ret = 0;
-+ struct ksmbd_user *user = new_ksmbd_user(name, pwd);
-+
-+ if (!user) {
-+ free(name);
-+ free(pwd);
-+ return -ENOMEM;
-+ }
-+
-+ g_rw_lock_writer_lock(&users_table_lock);
-+ if (__usm_lookup_user(name)) {
-+ g_rw_lock_writer_unlock(&users_table_lock);
-+ pr_info("User `%s' already exists\n", name);
-+ kill_ksmbd_user(user);
-+ return 0;
-+ }
-+
-+ pr_debug("New user `%s'\n", user->name);
-+ if (!g_hash_table_insert(users_table, user->name, user)) {
-+ kill_ksmbd_user(user);
-+ ret = -EINVAL;
-+ }
-+ g_rw_lock_writer_unlock(&users_table_lock);
-+ return ret;
-+}
-+
-+int usm_add_update_user_from_pwdentry(char *data)
-+{
-+ struct ksmbd_user *user;
-+ char *name;
-+ char *pwd;
-+ char *pos = strchr(data, ':');
-+ int ret;
-+
-+ if (!pos) {
-+ pr_err("Invalid pwd entry: %s\n", data);
-+ return -EINVAL;
-+ }
-+
-+ *pos = 0x00;
-+ name = g_strdup(data);
-+ pwd = g_strdup(pos + 1);
-+
-+ if (!name || !pwd) {
-+ free(name);
-+ free(pwd);
-+ return -ENOMEM;
-+ }
-+
-+ user = usm_lookup_user(name);
-+ if (user) {
-+ ret = usm_update_user_password(user, pwd);
-+ put_ksmbd_user(user);
-+
-+ free(name);
-+ free(pwd);
-+ return ret;
-+ }
-+ return usm_add_new_user(name, pwd);
-+}
-+
-+int usm_add_subauth_global_conf(char *data)
-+{
-+ char *pos = data;
-+ char *spos;
-+
-+ if (!pos)
-+ return -EINVAL;
-+
-+ spos = strchr(pos, ':');
-+ if (!spos) {
-+ pr_err("Invalid subauth entry: %s\n", data);
-+ return -EINVAL;
-+ }
-+
-+ *spos = 0x00;
-+ global_conf.gen_subauth[0] = atoi(pos);
-+ pos = spos + 1;
-+
-+ spos = strchr(pos, ':');
-+ if (!spos) {
-+ pr_err("Invalid subauth entry: %s\n", data);
-+ return -EINVAL;
-+ }
-+ *spos = 0x00;
-+ global_conf.gen_subauth[1] = atoi(pos);
-+ global_conf.gen_subauth[2] = atoi(spos + 1);
-+
-+ return 0;
-+}
-+
-+void for_each_ksmbd_user(walk_users cb, gpointer user_data)
-+{
-+ g_rw_lock_reader_lock(&users_table_lock);
-+ g_hash_table_foreach(users_table, cb, user_data);
-+ g_rw_lock_reader_unlock(&users_table_lock);
-+}
-+
-+int usm_update_user_password(struct ksmbd_user *user, char *pswd)
-+{
-+ size_t pass_sz;
-+ char *pass_b64 = g_strdup(pswd);
-+ char *pass = base64_decode(pass_b64, &pass_sz);
-+
-+ if (!pass_b64 || !pass) {
-+ free(pass_b64);
-+ free(pass);
-+ pr_err("Out of memory\n");
-+ return -ENOMEM;
-+ }
-+
-+ pr_debug("Update user password: %s\n", user->name);
-+ g_rw_lock_writer_lock(&user->update_lock);
-+ free(user->pass_b64);
-+ free(user->pass);
-+ user->pass_b64 = pass_b64;
-+ user->pass = pass;
-+ user->pass_sz = (int)pass_sz;
-+ g_rw_lock_writer_unlock(&user->update_lock);
-+
-+ return 0;
-+}
-+
-+static int usm_copy_user_passhash(struct ksmbd_user *user,
-+ char *pass,
-+ size_t sz)
-+{
-+ int ret = -ENOSPC;
-+
-+ if (test_user_flag(user, KSMBD_USER_FLAG_GUEST_ACCOUNT))
-+ return 0;
-+
-+ g_rw_lock_reader_lock(&user->update_lock);
-+ if (sz >= user->pass_sz) {
-+ memcpy(pass, user->pass, user->pass_sz);
-+ ret = user->pass_sz;
-+ }
-+ g_rw_lock_reader_unlock(&user->update_lock);
-+
-+ return ret;
-+}
-+
-+static int usm_copy_user_account(struct ksmbd_user *user,
-+ char *account,
-+ size_t sz)
-+{
-+ int account_sz;
-+
-+ if (test_user_flag(user, KSMBD_USER_FLAG_GUEST_ACCOUNT))
-+ return 0;
-+
-+ account_sz = strlen(user->name);
-+ if (sz >= account_sz) {
-+ memcpy(account, user->name, account_sz);
-+ return 0;
-+ }
-+ pr_err("Cannot copy user data, buffer overrun\n");
-+ return -ENOSPC;
-+}
-+
-+static void __handle_login_request(struct ksmbd_login_response *resp,
-+ struct ksmbd_user *user)
-+{
-+ int hash_sz;
-+
-+ resp->gid = user->gid;
-+ resp->uid = user->uid;
-+ resp->status = user->flags;
-+ resp->status |= KSMBD_USER_FLAG_OK;
-+
-+ hash_sz = usm_copy_user_passhash(user,
-+ resp->hash,
-+ sizeof(resp->hash));
-+ if (hash_sz < 0) {
-+ resp->status = KSMBD_USER_FLAG_INVALID;
-+ } else {
-+ resp->hash_sz = (unsigned short)hash_sz;
-+ if (usm_copy_user_account(user,
-+ resp->account,
-+ sizeof(resp->account)))
-+ resp->status = KSMBD_USER_FLAG_INVALID;
-+ }
-+}
-+
-+int usm_handle_login_request(struct ksmbd_login_request *req,
-+ struct ksmbd_login_response *resp)
-+{
-+ struct ksmbd_user *user = NULL;
-+ int null_session = 0;
-+
-+ if (req->account[0] == '\0')
-+ null_session = 1;
-+
-+ if (!null_session)
-+ user = usm_lookup_user(req->account);
-+ if (user) {
-+ __handle_login_request(resp, user);
-+ put_ksmbd_user(user);
-+ return 0;
-+ }
-+
-+ resp->status = KSMBD_USER_FLAG_BAD_USER;
-+ if (!null_session &&
-+ global_conf.map_to_guest == KSMBD_CONF_MAP_TO_GUEST_NEVER)
-+ return 0;
-+
-+ if (null_session ||
-+ global_conf.map_to_guest == KSMBD_CONF_MAP_TO_GUEST_BAD_USER)
-+ user = usm_lookup_user(global_conf.guest_account);
-+
-+ if (!user)
-+ return 0;
-+
-+ __handle_login_request(resp, user);
-+ put_ksmbd_user(user);
-+ return 0;
-+}
-+
-+int usm_handle_logout_request(struct ksmbd_logout_request *req)
-+{
-+ struct ksmbd_user *user;
-+
-+ user = usm_lookup_user(req->account);
-+ if (!user)
-+ return -ENOENT;
-+
-+ if (req->account_flags & KSMBD_USER_FLAG_BAD_PASSWORD) {
-+ if (user->failed_login_count < 10)
-+ user->failed_login_count++;
-+ else
-+ user->flags |= KSMBD_USER_FLAG_DELAY_SESSION;
-+ } else {
-+ user->failed_login_count = 0;
-+ user->flags &= ~KSMBD_USER_FLAG_DELAY_SESSION;
-+ }
-+
-+ put_ksmbd_user(user);
-+ return 0;
-+}
---- a/lib/meson.build
-+++ /dev/null
-@@ -1,31 +0,0 @@
--core_files = [
-- 'management/tree_conn.c',
-- 'management/user.c',
-- 'management/share.c',
-- 'management/session.c',
-- 'config_parser.c',
-- 'ksmbdtools.c',
--]
--
--if krb5_dep.found()
-- core_files += [
-- 'management/spnego.c',
-- 'asn1.c',
-- 'management/spnego_krb5.c',
-- ]
--endif
--
--libksmbdtools = static_library(
-- 'ksmbdtools',
-- core_files,
-- include_directories: tools_incdir,
-- dependencies: [
-- glib_dep,
-- krb5_dep,
-- asn1_lib,
-- ],
-- c_args: [
-- '-DSYSCONFDIR="@0@"'.format(get_option('prefix') / get_option('sysconfdir')),
-- '-DRUNSTATEDIR="@0@"'.format(runstatedir),
-- ],
--)
---- /dev/null
-+++ b/tools/meson.build
-@@ -0,0 +1,39 @@
-+ksmbd_tools_files = [
-+ 'management/tree_conn.c',
-+ 'management/user.c',
-+ 'management/share.c',
-+ 'management/session.c',
-+ 'config_parser.c',
-+ 'tools.c',
-+]
-+
-+if krb5_dep.found()
-+ ksmbd_tools_files += [
-+ 'management/spnego.c',
-+ 'asn1.c',
-+ 'management/spnego_krb5.c',
-+ ]
-+endif
-+
-+executable(
-+ 'ksmbd.tools',
-+ ksmbd_tools_files,
-+ include_directories: include_dirs,
-+ c_args: [
-+ '-DSYSCONFDIR="@0@"'.format(get_option('prefix') / get_option('sysconfdir')),
-+ '-DRUNSTATEDIR="@0@"'.format(runstatedir),
-+ ],
-+ dependencies: [
-+ glib_dep,
-+ krb5_dep,
-+ asn1_lib,
-+ ],
-+ link_with: [
-+ addshare_lib,
-+ adduser_lib,
-+ control_lib,
-+ mountd_lib,
-+ ],
-+ install: true,
-+ install_dir: get_option('libexecdir'),
-+)
---- a/lib/ksmbdtools.c
-+++ /dev/null
-@@ -1,276 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0-or-later
--/*
-- * Copyright (C) 2018 Samsung Electronics Co., Ltd.
-- *
-- * linux-cifsd-devel@lists.sourceforge.net
-- */
--
--#include <syslog.h>
--
--#include <unistd.h>
--#include <sys/stat.h>
--#include <fcntl.h>
--
--#include <stdio.h>
--#include <ksmbdtools.h>
--
--int log_level = PR_INFO;
--int ksmbd_health_status;
--
--static const char *app_name = "unknown";
--static int log_open;
--
--typedef void (*logger)(int level, const char *fmt, va_list list);
--
--char *ksmbd_conv_charsets[KSMBD_CHARSET_MAX + 1] = {
-- "UTF-8",
-- "UTF-16LE",
-- "UCS-2LE",
-- "UTF-16BE",
-- "UCS-2BE",
-- "OOPS"
--};
--
--static int syslog_level(int level)
--{
-- if (level == PR_ERROR)
-- return LOG_ERR;
-- if (level == PR_INFO)
-- return LOG_INFO;
-- if (level == PR_DEBUG)
-- return LOG_DEBUG;
--
-- return LOG_ERR;
--}
--
--G_GNUC_PRINTF(2, 0)
--static void __pr_log_stdio(int level, const char *fmt, va_list list)
--{
-- char buf[1024];
--
-- vsnprintf(buf, sizeof(buf), fmt, list);
-- printf("%s", buf);
--}
--
--G_GNUC_PRINTF(2, 0)
--static void __pr_log_syslog(int level, const char *fmt, va_list list)
--{
-- vsyslog(syslog_level(level), fmt, list);
--}
--
--static logger __logger = __pr_log_stdio;
--
--void set_logger_app_name(const char *an)
--{
-- app_name = an;
--}
--
--const char *get_logger_app_name(void)
--{
-- return app_name;
--}
--
--void __pr_log(int level, const char *fmt, ...)
--{
-- va_list list;
--
-- va_start(list, fmt);
-- __logger(level, fmt, list);
-- va_end(list);
--}
--
--void pr_logger_init(int flag)
--{
-- if (flag == PR_LOGGER_SYSLOG) {
-- if (log_open) {
-- closelog();
-- log_open = 0;
-- }
-- openlog("ksmbd", LOG_NDELAY, LOG_LOCAL5);
-- __logger = __pr_log_syslog;
-- log_open = 1;
-- }
--}
--
--int set_log_level(int level)
--{
-- int old_level;
--
-- if (log_level == PR_DEBUG)
-- return log_level;
--
-- old_level = log_level;
-- log_level = level;
-- return old_level;
--}
--
--#if TRACING_DUMP_NL_MSG
--#define PR_HEX_DUMP_WIDTH 160
--void pr_hex_dump(const void *mem, size_t sz)
--{
-- char xline[PR_HEX_DUMP_WIDTH];
-- char sline[PR_HEX_DUMP_WIDTH];
-- int xi = 0, si = 0, mi = 0;
--
-- while (mi < sz) {
-- char c = *((char *)mem + mi);
--
-- mi++;
-- xi += sprintf(xline + xi, "%02X ", 0xff & c);
-- if (c > ' ' && c < '~')
-- si += sprintf(sline + si, "%c", c);
-- else
-- si += sprintf(sline + si, ".");
-- if (xi >= PR_HEX_DUMP_WIDTH / 2) {
-- pr_err("%s %s\n", xline, sline);
-- xi = 0;
-- si = 0;
-- }
-- }
--
-- if (xi) {
-- int sz = PR_HEX_DUMP_WIDTH / 2 - xi + 1;
--
-- if (sz > 0) {
-- memset(xline + xi, ' ', sz);
-- xline[PR_HEX_DUMP_WIDTH / 2 + 1] = 0x00;
-- }
-- pr_err("%s %s\n", xline, sline);
-- }
--}
--#else
--void pr_hex_dump(const void *mem, size_t sz)
--{
--}
--#endif
--
--char *base64_encode(unsigned char *src, size_t srclen)
--{
-- return g_base64_encode(src, srclen);
--}
--
--unsigned char *base64_decode(char const *src, size_t *dstlen)
--{
-- unsigned char *ret = g_base64_decode(src, dstlen);
--
-- if (ret)
-- ret[*dstlen] = 0x00;
-- return ret;
--}
--
--static int codeset_has_altname(int codeset)
--{
-- if (codeset == KSMBD_CHARSET_UTF16LE ||
-- codeset == KSMBD_CHARSET_UTF16BE)
-- return 1;
-- return 0;
--}
--
--gchar *ksmbd_gconvert(const gchar *str,
-- gssize str_len,
-- int to_codeset,
-- int from_codeset,
-- gsize *bytes_read,
-- gsize *bytes_written)
--{
-- gchar *converted;
-- GError *err;
--
--retry:
-- err = NULL;
-- if (from_codeset >= KSMBD_CHARSET_MAX) {
-- pr_err("Unknown source codeset: %d\n", from_codeset);
-- return NULL;
-- }
--
-- if (to_codeset >= KSMBD_CHARSET_MAX) {
-- pr_err("Unknown target codeset: %d\n", to_codeset);
-- return NULL;
-- }
--
-- converted = g_convert(str,
-- str_len,
-- ksmbd_conv_charsets[to_codeset],
-- ksmbd_conv_charsets[from_codeset],
-- bytes_read,
-- bytes_written,
-- &err);
-- if (err) {
-- int has_altname = 0;
--
-- if (codeset_has_altname(to_codeset)) {
-- to_codeset++;
-- has_altname = 1;
-- }
--
-- if (codeset_has_altname(from_codeset)) {
-- from_codeset++;
-- has_altname = 1;
-- }
--
-- pr_info("%s\n", err->message);
-- g_error_free(err);
--
-- if (has_altname) {
-- pr_info("Will try `%s' and `%s'\n",
-- ksmbd_conv_charsets[to_codeset],
-- ksmbd_conv_charsets[from_codeset]);
-- goto retry;
-- }
--
-- pr_err("Can't convert string: %s\n", err->message);
-- g_error_free(err);
-- return NULL;
-- }
--
-- return converted;
--}
--
--int send_signal_to_ksmbd_mountd(int signo)
--{
-- int fd, ret = -EINVAL;
-- char pid_buf[10] = {0};
-- int pid;
--
-- fd = open(KSMBD_LOCK_FILE, O_RDONLY);
-- if (fd < 0) {
-- pr_debug("Can't open `%s': %m\n", KSMBD_LOCK_FILE);
-- return ret;
-- }
--
-- if (read(fd, &pid_buf, sizeof(pid_buf)) == -1) {
-- pr_err("Can't read manager PID: %m\n");
-- goto out;
-- }
--
-- pid = strtol(pid_buf, NULL, 10);
-- if (signo)
-- pr_debug("Send signal %d (%s) to PID %d\n",
-- signo, strsignal(signo), pid);
-- if (kill(pid, signo) == -1) {
-- ret = -errno;
-- if (signo)
-- pr_err("Unable to send signal %d (%s) to PID %d: %m\n",
-- signo, strsignal(signo), pid);
-- goto out;
-- }
--
-- ret = 0;
--out:
-- close(fd);
-- return ret;
--}
--
--int test_file_access(char *conf)
--{
-- int fd;
--
-- fd = open(conf, O_RDWR | O_CREAT, S_IRWXU | S_IRGRP);
-- if (fd < 0) {
-- pr_debug("Can't open `%s': %m\n", conf);
-- return -EINVAL;
-- }
--
-- close(fd);
-- return 0;
--}
---- /dev/null
-+++ b/tools/tools.c
-@@ -0,0 +1,301 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+/*
-+ * Copyright (C) 2018 Samsung Electronics Co., Ltd.
-+ *
-+ * linux-cifsd-devel@lists.sourceforge.net
-+ */
-+
-+#include <syslog.h>
-+
-+#include <unistd.h>
-+#include <sys/stat.h>
-+#include <fcntl.h>
-+
-+#include <stdio.h>
-+#include <tools.h>
-+
-+int log_level = PR_INFO;
-+int ksmbd_health_status;
-+
-+static const char *app_name = "unknown";
-+static int log_open;
-+
-+typedef void (*logger)(int level, const char *fmt, va_list list);
-+
-+char *ksmbd_conv_charsets[KSMBD_CHARSET_MAX + 1] = {
-+ "UTF-8",
-+ "UTF-16LE",
-+ "UCS-2LE",
-+ "UTF-16BE",
-+ "UCS-2BE",
-+ "OOPS"
-+};
-+
-+static int syslog_level(int level)
-+{
-+ if (level == PR_ERROR)
-+ return LOG_ERR;
-+ if (level == PR_INFO)
-+ return LOG_INFO;
-+ if (level == PR_DEBUG)
-+ return LOG_DEBUG;
-+
-+ return LOG_ERR;
-+}
-+
-+G_GNUC_PRINTF(2, 0)
-+static void __pr_log_stdio(int level, const char *fmt, va_list list)
-+{
-+ char buf[1024];
-+
-+ vsnprintf(buf, sizeof(buf), fmt, list);
-+ printf("%s", buf);
-+}
-+
-+G_GNUC_PRINTF(2, 0)
-+static void __pr_log_syslog(int level, const char *fmt, va_list list)
-+{
-+ vsyslog(syslog_level(level), fmt, list);
-+}
-+
-+static logger __logger = __pr_log_stdio;
-+
-+void set_logger_app_name(const char *an)
-+{
-+ app_name = an;
-+}
-+
-+const char *get_logger_app_name(void)
-+{
-+ return app_name;
-+}
-+
-+void __pr_log(int level, const char *fmt, ...)
-+{
-+ va_list list;
-+
-+ va_start(list, fmt);
-+ __logger(level, fmt, list);
-+ va_end(list);
-+}
-+
-+void pr_logger_init(int flag)
-+{
-+ if (flag == PR_LOGGER_SYSLOG) {
-+ if (log_open) {
-+ closelog();
-+ log_open = 0;
-+ }
-+ openlog("ksmbd", LOG_NDELAY, LOG_LOCAL5);
-+ __logger = __pr_log_syslog;
-+ log_open = 1;
-+ }
-+}
-+
-+int set_log_level(int level)
-+{
-+ int old_level;
-+
-+ if (log_level == PR_DEBUG)
-+ return log_level;
-+
-+ old_level = log_level;
-+ log_level = level;
-+ return old_level;
-+}
-+
-+#if TRACING_DUMP_NL_MSG
-+#define PR_HEX_DUMP_WIDTH 160
-+void pr_hex_dump(const void *mem, size_t sz)
-+{
-+ char xline[PR_HEX_DUMP_WIDTH];
-+ char sline[PR_HEX_DUMP_WIDTH];
-+ int xi = 0, si = 0, mi = 0;
-+
-+ while (mi < sz) {
-+ char c = *((char *)mem + mi);
-+
-+ mi++;
-+ xi += sprintf(xline + xi, "%02X ", 0xff & c);
-+ if (c > ' ' && c < '~')
-+ si += sprintf(sline + si, "%c", c);
-+ else
-+ si += sprintf(sline + si, ".");
-+ if (xi >= PR_HEX_DUMP_WIDTH / 2) {
-+ pr_err("%s %s\n", xline, sline);
-+ xi = 0;
-+ si = 0;
-+ }
-+ }
-+
-+ if (xi) {
-+ int sz = PR_HEX_DUMP_WIDTH / 2 - xi + 1;
-+
-+ if (sz > 0) {
-+ memset(xline + xi, ' ', sz);
-+ xline[PR_HEX_DUMP_WIDTH / 2 + 1] = 0x00;
-+ }
-+ pr_err("%s %s\n", xline, sline);
-+ }
-+}
-+#else
-+void pr_hex_dump(const void *mem, size_t sz)
-+{
-+}
-+#endif
-+
-+char *base64_encode(unsigned char *src, size_t srclen)
-+{
-+ return g_base64_encode(src, srclen);
-+}
-+
-+unsigned char *base64_decode(char const *src, size_t *dstlen)
-+{
-+ unsigned char *ret = g_base64_decode(src, dstlen);
-+
-+ if (ret)
-+ ret[*dstlen] = 0x00;
-+ return ret;
-+}
-+
-+static int codeset_has_altname(int codeset)
-+{
-+ if (codeset == KSMBD_CHARSET_UTF16LE ||
-+ codeset == KSMBD_CHARSET_UTF16BE)
-+ return 1;
-+ return 0;
-+}
-+
-+gchar *ksmbd_gconvert(const gchar *str,
-+ gssize str_len,
-+ int to_codeset,
-+ int from_codeset,
-+ gsize *bytes_read,
-+ gsize *bytes_written)
-+{
-+ gchar *converted;
-+ GError *err;
-+
-+retry:
-+ err = NULL;
-+ if (from_codeset >= KSMBD_CHARSET_MAX) {
-+ pr_err("Unknown source codeset: %d\n", from_codeset);
-+ return NULL;
-+ }
-+
-+ if (to_codeset >= KSMBD_CHARSET_MAX) {
-+ pr_err("Unknown target codeset: %d\n", to_codeset);
-+ return NULL;
-+ }
-+
-+ converted = g_convert(str,
-+ str_len,
-+ ksmbd_conv_charsets[to_codeset],
-+ ksmbd_conv_charsets[from_codeset],
-+ bytes_read,
-+ bytes_written,
-+ &err);
-+ if (err) {
-+ int has_altname = 0;
-+
-+ if (codeset_has_altname(to_codeset)) {
-+ to_codeset++;
-+ has_altname = 1;
-+ }
-+
-+ if (codeset_has_altname(from_codeset)) {
-+ from_codeset++;
-+ has_altname = 1;
-+ }
-+
-+ pr_info("%s\n", err->message);
-+ g_error_free(err);
-+
-+ if (has_altname) {
-+ pr_info("Will try `%s' and `%s'\n",
-+ ksmbd_conv_charsets[to_codeset],
-+ ksmbd_conv_charsets[from_codeset]);
-+ goto retry;
-+ }
-+
-+ pr_err("Can't convert string: %s\n", err->message);
-+ g_error_free(err);
-+ return NULL;
-+ }
-+
-+ return converted;
-+}
-+
-+int send_signal_to_ksmbd_mountd(int signo)
-+{
-+ int fd, ret = -EINVAL;
-+ char pid_buf[10] = {0};
-+ int pid;
-+
-+ fd = open(KSMBD_LOCK_FILE, O_RDONLY);
-+ if (fd < 0) {
-+ pr_debug("Can't open `%s': %m\n", KSMBD_LOCK_FILE);
-+ return ret;
-+ }
-+
-+ if (read(fd, &pid_buf, sizeof(pid_buf)) == -1) {
-+ pr_err("Can't read manager PID: %m\n");
-+ goto out;
-+ }
-+
-+ pid = strtol(pid_buf, NULL, 10);
-+ if (signo)
-+ pr_debug("Send signal %d (%s) to PID %d\n",
-+ signo, strsignal(signo), pid);
-+ if (kill(pid, signo) == -1) {
-+ ret = -errno;
-+ if (signo)
-+ pr_err("Unable to send signal %d (%s) to PID %d: %m\n",
-+ signo, strsignal(signo), pid);
-+ goto out;
-+ }
-+
-+ ret = 0;
-+out:
-+ close(fd);
-+ return ret;
-+}
-+
-+int test_file_access(char *conf)
-+{
-+ int fd;
-+
-+ fd = open(conf, O_RDWR | O_CREAT, S_IRWXU | S_IRGRP);
-+ if (fd < 0) {
-+ pr_debug("Can't open `%s': %m\n", conf);
-+ return -EINVAL;
-+ }
-+
-+ close(fd);
-+ return 0;
-+}
-+
-+int main(int argc, char **argv)
-+{
-+ char *base_name;
-+
-+ set_logger_app_name("ksmbd.tools");
-+
-+ if (!*argv)
-+ return EXIT_FAILURE;
-+
-+ base_name = strrchr(*argv, '/');
-+ base_name = base_name ? base_name + 1 : *argv;
-+
-+ if (!strcmp(base_name, "ksmbd.addshare"))
-+ return addshare_main(argc, argv);
-+ if (!strcmp(base_name, "ksmbd.adduser"))
-+ return adduser_main(argc, argv);
-+ if (!strcmp(base_name, "ksmbd.control"))
-+ return control_main(argc, argv);
-+ if (!strcmp(base_name, "ksmbd.mountd"))
-+ return mountd_main(argc, argv);
-+
-+ pr_err("Unknown base name: %s\n", base_name);
-+ return EXIT_FAILURE;
-+}
---- a/lib/asn1.c
-+++ /dev/null
-@@ -1,391 +0,0 @@
--// SPDX-License-Identifier: GPL-2.0-or-later
--/*
-- * The ASB.1/BER parsing code is derived from ip_nat_snmp_basic.c which was in
-- * turn derived from the gxsnmp package by Gregory McLean & Jochen Friedrich
-- *
-- * Copyright (c) 2000 RP Internet (www.rpi.net.au).
-- */
--
--/*****************************************************************************
-- *
-- * Basic ASN.1 decoding routines (gxsnmp author Dirk Wisse)
-- *
-- *****************************************************************************/
--#include <stdlib.h>
--#include <limits.h>
--#include <string.h>
--#include <errno.h>
--#include <glib.h>
--
--#include "asn1.h"
--
--void
--asn1_open(struct asn1_ctx *ctx, unsigned char *buf, unsigned int len)
--{
-- ctx->begin = buf;
-- ctx->end = buf + len;
-- ctx->pointer = buf;
-- ctx->error = ASN1_ERR_NOERROR;
--}
--
--static unsigned char
--asn1_octet_decode(struct asn1_ctx *ctx, unsigned char *ch)
--{
-- if (ctx->pointer >= ctx->end) {
-- ctx->error = ASN1_ERR_DEC_EMPTY;
-- return 0;
-- }
-- *ch = *(ctx->pointer)++;
-- return 1;
--}
--
--static unsigned char
--asn1_tag_decode(struct asn1_ctx *ctx, unsigned int *tag)
--{
-- unsigned char ch;
--
-- *tag = 0;
--
-- do {
-- if (!asn1_octet_decode(ctx, &ch))
-- return 0;
-- *tag <<= 7;
-- *tag |= ch & 0x7F;
-- } while ((ch & 0x80) == 0x80);
-- return 1;
--}
--
--static unsigned char
--asn1_id_decode(struct asn1_ctx *ctx,
-- unsigned int *cls, unsigned int *con, unsigned int *tag)
--{
-- unsigned char ch;
--
-- if (!asn1_octet_decode(ctx, &ch))
-- return 0;
--
-- *cls = (ch & 0xC0) >> 6;
-- *con = (ch & 0x20) >> 5;
-- *tag = (ch & 0x1F);
--
-- if (*tag == 0x1F) {
-- if (!asn1_tag_decode(ctx, tag))
-- return 0;
-- }
-- return 1;
--}
--
--static unsigned char
--asn1_length_decode(struct asn1_ctx *ctx, unsigned int *def, unsigned int *len)
--{
-- unsigned char ch, cnt;
--
-- if (!asn1_octet_decode(ctx, &ch))
-- return 0;
--
-- if (ch == 0x80)
-- *def = 0;
-- else {
-- *def = 1;
--
-- if (ch < 0x80)
-- *len = ch;
-- else {
-- cnt = (unsigned char) (ch & 0x7F);
-- *len = 0;
--
-- while (cnt > 0) {
-- if (!asn1_octet_decode(ctx, &ch))
-- return 0;
-- *len <<= 8;
-- *len |= ch;
-- cnt--;
-- }
-- }
-- }
--
-- /* don't trust len bigger than ctx buffer */
-- if (*len > ctx->end - ctx->pointer)
-- return 0;
--
-- return 1;
--}
--
--unsigned char
--asn1_header_decode(struct asn1_ctx *ctx,
-- unsigned char **eoc,
-- unsigned int *cls, unsigned int *con, unsigned int *tag)
--{
-- unsigned int def = 0;
-- unsigned int len = 0;
--
-- if (!asn1_id_decode(ctx, cls, con, tag))
-- return 0;
--
-- if (!asn1_length_decode(ctx, &def, &len))
-- return 0;
--
-- /* primitive shall be definite, indefinite shall be constructed */
-- if (*con == ASN1_PRI && !def)
-- return 0;
--
-- if (def)
-- *eoc = ctx->pointer + len;
-- else
-- *eoc = NULL;
-- return 1;
--}
--
--static unsigned char
--asn1_eoc_decode(struct asn1_ctx *ctx, unsigned char *eoc)
--{
-- unsigned char ch;
--
-- if (eoc == NULL) {
-- if (!asn1_octet_decode(ctx, &ch))
-- return 0;
--
-- if (ch != 0x00) {
-- ctx->error = ASN1_ERR_DEC_EOC_MISMATCH;
-- return 0;
-- }
--
-- if (!asn1_octet_decode(ctx, &ch))
-- return 0;
--
-- if (ch != 0x00) {
-- ctx->error = ASN1_ERR_DEC_EOC_MISMATCH;
-- return 0;
-- }
-- return 1;
-- }
--
-- if (ctx->pointer != eoc) {
-- ctx->error = ASN1_ERR_DEC_LENGTH_MISMATCH;
-- return 0;
-- }
-- return 1;
--}
--
--unsigned char
--asn1_octets_decode(struct asn1_ctx *ctx,
-- unsigned char *eoc,
-- unsigned char **octets, unsigned int *len)
--{
-- unsigned char *ptr;
--
-- *len = 0;
--
-- *octets = malloc(eoc - ctx->pointer);
-- if (*octets == NULL)
-- return 0;
--
-- ptr = *octets;
-- while (ctx->pointer < eoc) {
-- if (!asn1_octet_decode(ctx, (unsigned char *) ptr++)) {
-- free(*octets);
-- *octets = NULL;
-- return 0;
-- }
-- (*len)++;
-- }
-- return 1;
--}
--
--unsigned char asn1_read(struct asn1_ctx *ctx,
-- unsigned char **buf, unsigned int len)
--{
-- *buf = NULL;
-- if (ctx->end - ctx->pointer < len) {
-- ctx->error = ASN1_ERR_DEC_EMPTY;
-- return 0;
-- }
--
-- *buf = malloc(len);
-- if (!*buf)
-- return 0;
-- memcpy(*buf, ctx->pointer, len);
-- ctx->pointer += len;
-- return 1;
--}
--
--static unsigned char
--asn1_subid_decode(struct asn1_ctx *ctx, unsigned long *subid)
--{
-- unsigned char ch;
--
-- *subid = 0;
--
-- do {
-- if (!asn1_octet_decode(ctx, &ch))
-- return 0;
--
-- *subid <<= 7;
-- *subid |= ch & 0x7F;
-- } while ((ch & 0x80) == 0x80);
-- return 1;
--}
--
--int
--asn1_oid_decode(struct asn1_ctx *ctx,
-- unsigned char *eoc, unsigned long **oid, unsigned int *len)
--{
-- unsigned long subid;
-- unsigned int size;
-- unsigned long *optr;
--
-- size = eoc - ctx->pointer + 1;
--
-- /* first subid actually encodes first two subids */
-- if (size < 2 || size > UINT_MAX/sizeof(unsigned long))
-- return 0;
--
-- *oid = g_try_malloc0_n(size, sizeof(unsigned long));
-- if (*oid == NULL)
-- return 0;
--
-- optr = *oid;
--
-- if (!asn1_subid_decode(ctx, &subid)) {
-- g_free(*oid);
-- *oid = NULL;
-- return 0;
-- }
--
-- if (subid < 40) {
-- optr[0] = 0;
-- optr[1] = subid;
-- } else if (subid < 80) {
-- optr[0] = 1;
-- optr[1] = subid - 40;
-- } else {
-- optr[0] = 2;
-- optr[1] = subid - 80;
-- }
--
-- *len = 2;
-- optr += 2;
--
-- while (ctx->pointer < eoc) {
-- if (++(*len) > size) {
-- ctx->error = ASN1_ERR_DEC_BADVALUE;
-- g_free(*oid);
-- *oid = NULL;
-- return 0;
-- }
--
-- if (!asn1_subid_decode(ctx, optr++)) {
-- g_free(*oid);
-- *oid = NULL;
-- return 0;
-- }
-- }
-- return 1;
--}
--
--/* return the size of @depth-nested headers + payload */
--int asn1_header_len(unsigned int payload_len, int depth)
--{
-- unsigned int len;
-- int i;
--
-- len = payload_len;
-- for (i = 0; i < depth; i++) {
-- /* length */
-- if (len >= (1 << 24))
-- len += 5;
-- else if (len >= (1 << 16))
-- len += 4;
-- else if (len >= (1 << 8))
-- len += 3;
-- else if (len >= (1 << 7))
-- len += 2;
-- else
-- len += 1;
-- /* 1-byte header */
-- len += 1;
-- }
-- return len;
--}
--
--int asn1_oid_encode(const unsigned long *in_oid, int in_len,
-- unsigned char **out_oid, int *out_len)
--{
-- unsigned char *oid;
-- unsigned long id;
-- int i;
--
-- *out_oid = g_try_malloc0_n(in_len, 5);
-- if (*out_oid == NULL)
-- return -ENOMEM;
--
-- oid = *out_oid;
-- *oid++ = (unsigned char)(40 * in_oid[0] + in_oid[1]);
-- for (i = 2; i < in_len; i++) {
-- id = in_oid[i];
-- if (id >= (1 << 28))
-- *oid++ = (0x80 | ((id>>28) & 0x7F));
-- if (id >= (1 << 21))
-- *oid++ = (0x80 | ((id>>21) & 0x7F));
-- if (id >= (1 << 14))
-- *oid++ = (0x80 | ((id>>14) & 0x7F));
-- if (id >= (1 << 7))
-- *oid++ = (0x80 | ((id>>7) & 0x7F));
-- *oid++ = id & 0x7F;
-- }
-- *out_len = (int)(oid - *out_oid);
-- return 0;
--}
--
--/*
-- * @len is the sum of all sizes of header, length and payload.
-- * it will be decreased by the sum of sizes of header and length.
-- */
--int asn1_header_encode(unsigned char **buf,
-- unsigned int cls, unsigned int con, unsigned int tag,
-- unsigned int *len)
--{
-- unsigned char *loc;
-- unsigned int r_len;
--
-- /* at least, 1-byte header + 1-byte length is needed. */
-- if (*len < 2)
-- return -EINVAL;
--
-- loc = *buf;
-- r_len = *len;
--
-- *loc++ = ((cls & 0x3) << 6) | ((con & 0x1) << 5) | (tag & 0x1F);
-- r_len -= 1;
--
-- if (r_len - 1 < (1 << 7)) {
-- r_len -= 1;
-- *loc++ = (unsigned char)(r_len & 0x7F);
-- } else if (r_len - 2 < (1 << 8)) {
-- r_len -= 2;
-- *loc++ = 0x81;
-- *loc++ = (unsigned char)(r_len & 0xFF);
-- } else if (r_len - 3 < (1 << 16)) {
-- r_len -= 3;
-- *loc++ = 0x82;
-- *loc++ = (unsigned char)((r_len>>8) & 0xFF);
-- *loc++ = (unsigned char)(r_len & 0xFF);
-- } else if (r_len - 4 < (1 << 24)) {
-- r_len -= 4;
-- *loc++ = 0x83;
-- *loc++ = (unsigned char)((r_len>>16) & 0xFF);
-- *loc++ = (unsigned char)((r_len>>8) & 0xFF);
-- *loc++ = (unsigned char)(r_len & 0xFF);
-- } else {
-- r_len -= 5;
-- *loc++ = 0x84;
-- *loc++ = (unsigned char)((r_len>>24) & 0xFF);
-- *loc++ = (unsigned char)((r_len>>16) & 0xFF);
-- *loc++ = (unsigned char)((r_len>>8) & 0xFF);
-- *loc++ = (unsigned char)(r_len & 0xFF);
-- }
--
-- *buf = loc;
-- *len = r_len;
-- return 0;
--}
---- a/lib/management/spnego_mech.h
-+++ /dev/null
-@@ -1,48 +0,0 @@
--/* SPDX-License-Identifier: GPL-2.0-or-later */
--/*
-- * Copyright (C) 2020 LG Electronics
-- *
-- * linux-cifsd-devel@lists.sourceforge.net
-- */
--
--#ifndef _SPNEGO_MECH_H_
--#define _SPNEGO_MECH_H_
--
--enum {
-- SPNEGO_MECH_MSKRB5 = 0,
-- SPNEGO_MECH_KRB5,
-- SPNEGO_MAX_MECHS,
--};
--
--struct spnego_mech_ctx;
--
--typedef int (*spnego_encode_t)(char *in_blob, int in_len,
-- const unsigned long *oid, int oid_len,
-- char **out_blob, int *out_len);
--
--struct spnego_mech_operations {
-- int (*setup)(struct spnego_mech_ctx *mech_ctx);
-- void (*cleanup)(struct spnego_mech_ctx *mech_ctx);
-- int (*handle_authen)(struct spnego_mech_ctx *mech_ctx,
-- char *in_blob, unsigned int in_len,
-- struct ksmbd_spnego_auth_out *auth_out,
-- spnego_encode_t encode);
--};
--
--struct spnego_mech_ctx {
-- const unsigned long *oid;
-- int oid_len;
-- void *private;
-- union {
-- struct {
-- void *keytab_name;
-- void *service_name;
-- } krb5;
-- } params;
-- struct spnego_mech_operations *ops;
--};
--
--extern struct spnego_mech_operations spnego_krb5_operations;
--extern struct spnego_mech_operations spnego_mskrb5_operations;
--
--#endif
---- /dev/null
-+++ b/tools/asn1.c
-@@ -0,0 +1,391 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+/*
-+ * The ASB.1/BER parsing code is derived from ip_nat_snmp_basic.c which was in
-+ * turn derived from the gxsnmp package by Gregory McLean & Jochen Friedrich
-+ *
-+ * Copyright (c) 2000 RP Internet (www.rpi.net.au).
-+ */
-+
-+/*****************************************************************************
-+ *
-+ * Basic ASN.1 decoding routines (gxsnmp author Dirk Wisse)
-+ *
-+ *****************************************************************************/
-+#include <stdlib.h>
-+#include <limits.h>
-+#include <string.h>
-+#include <errno.h>
-+#include <glib.h>
-+
-+#include "asn1.h"
-+
-+void
-+asn1_open(struct asn1_ctx *ctx, unsigned char *buf, unsigned int len)
-+{
-+ ctx->begin = buf;
-+ ctx->end = buf + len;
-+ ctx->pointer = buf;
-+ ctx->error = ASN1_ERR_NOERROR;
-+}
-+
-+static unsigned char
-+asn1_octet_decode(struct asn1_ctx *ctx, unsigned char *ch)
-+{
-+ if (ctx->pointer >= ctx->end) {
-+ ctx->error = ASN1_ERR_DEC_EMPTY;
-+ return 0;
-+ }
-+ *ch = *(ctx->pointer)++;
-+ return 1;
-+}
-+
-+static unsigned char
-+asn1_tag_decode(struct asn1_ctx *ctx, unsigned int *tag)
-+{
-+ unsigned char ch;
-+
-+ *tag = 0;
-+
-+ do {
-+ if (!asn1_octet_decode(ctx, &ch))
-+ return 0;
-+ *tag <<= 7;
-+ *tag |= ch & 0x7F;
-+ } while ((ch & 0x80) == 0x80);
-+ return 1;
-+}
-+
-+static unsigned char
-+asn1_id_decode(struct asn1_ctx *ctx,
-+ unsigned int *cls, unsigned int *con, unsigned int *tag)
-+{
-+ unsigned char ch;
-+
-+ if (!asn1_octet_decode(ctx, &ch))
-+ return 0;
-+
-+ *cls = (ch & 0xC0) >> 6;
-+ *con = (ch & 0x20) >> 5;
-+ *tag = (ch & 0x1F);
-+
-+ if (*tag == 0x1F) {
-+ if (!asn1_tag_decode(ctx, tag))
-+ return 0;
-+ }
-+ return 1;
-+}
-+
-+static unsigned char
-+asn1_length_decode(struct asn1_ctx *ctx, unsigned int *def, unsigned int *len)
-+{
-+ unsigned char ch, cnt;
-+
-+ if (!asn1_octet_decode(ctx, &ch))
-+ return 0;
-+
-+ if (ch == 0x80)
-+ *def = 0;
-+ else {
-+ *def = 1;
-+
-+ if (ch < 0x80)
-+ *len = ch;
-+ else {
-+ cnt = (unsigned char) (ch & 0x7F);
-+ *len = 0;
-+
-+ while (cnt > 0) {
-+ if (!asn1_octet_decode(ctx, &ch))
-+ return 0;
-+ *len <<= 8;
-+ *len |= ch;
-+ cnt--;
-+ }
-+ }
-+ }
-+
-+ /* don't trust len bigger than ctx buffer */
-+ if (*len > ctx->end - ctx->pointer)
-+ return 0;
-+
-+ return 1;
-+}
-+
-+unsigned char
-+asn1_header_decode(struct asn1_ctx *ctx,
-+ unsigned char **eoc,
-+ unsigned int *cls, unsigned int *con, unsigned int *tag)
-+{
-+ unsigned int def = 0;
-+ unsigned int len = 0;
-+
-+ if (!asn1_id_decode(ctx, cls, con, tag))
-+ return 0;
-+
-+ if (!asn1_length_decode(ctx, &def, &len))
-+ return 0;
-+
-+ /* primitive shall be definite, indefinite shall be constructed */
-+ if (*con == ASN1_PRI && !def)
-+ return 0;
-+
-+ if (def)
-+ *eoc = ctx->pointer + len;
-+ else
-+ *eoc = NULL;
-+ return 1;
-+}
-+
-+static unsigned char
-+asn1_eoc_decode(struct asn1_ctx *ctx, unsigned char *eoc)
-+{
-+ unsigned char ch;
-+
-+ if (eoc == NULL) {
-+ if (!asn1_octet_decode(ctx, &ch))
-+ return 0;
-+
-+ if (ch != 0x00) {
-+ ctx->error = ASN1_ERR_DEC_EOC_MISMATCH;
-+ return 0;
-+ }
-+
-+ if (!asn1_octet_decode(ctx, &ch))
-+ return 0;
-+
-+ if (ch != 0x00) {
-+ ctx->error = ASN1_ERR_DEC_EOC_MISMATCH;
-+ return 0;
-+ }
-+ return 1;
-+ }
-+
-+ if (ctx->pointer != eoc) {
-+ ctx->error = ASN1_ERR_DEC_LENGTH_MISMATCH;
-+ return 0;
-+ }
-+ return 1;
-+}
-+
-+unsigned char
-+asn1_octets_decode(struct asn1_ctx *ctx,
-+ unsigned char *eoc,
-+ unsigned char **octets, unsigned int *len)
-+{
-+ unsigned char *ptr;
-+
-+ *len = 0;
-+
-+ *octets = malloc(eoc - ctx->pointer);
-+ if (*octets == NULL)
-+ return 0;
-+
-+ ptr = *octets;
-+ while (ctx->pointer < eoc) {
-+ if (!asn1_octet_decode(ctx, (unsigned char *) ptr++)) {
-+ free(*octets);
-+ *octets = NULL;
-+ return 0;
-+ }
-+ (*len)++;
-+ }
-+ return 1;
-+}
-+
-+unsigned char asn1_read(struct asn1_ctx *ctx,
-+ unsigned char **buf, unsigned int len)
-+{
-+ *buf = NULL;
-+ if (ctx->end - ctx->pointer < len) {
-+ ctx->error = ASN1_ERR_DEC_EMPTY;
-+ return 0;
-+ }
-+
-+ *buf = malloc(len);
-+ if (!*buf)
-+ return 0;
-+ memcpy(*buf, ctx->pointer, len);
-+ ctx->pointer += len;
-+ return 1;
-+}
-+
-+static unsigned char
-+asn1_subid_decode(struct asn1_ctx *ctx, unsigned long *subid)
-+{
-+ unsigned char ch;
-+
-+ *subid = 0;
-+
-+ do {
-+ if (!asn1_octet_decode(ctx, &ch))
-+ return 0;
-+
-+ *subid <<= 7;
-+ *subid |= ch & 0x7F;
-+ } while ((ch & 0x80) == 0x80);
-+ return 1;
-+}
-+
-+int
-+asn1_oid_decode(struct asn1_ctx *ctx,
-+ unsigned char *eoc, unsigned long **oid, unsigned int *len)
-+{
-+ unsigned long subid;
-+ unsigned int size;
-+ unsigned long *optr;
-+
-+ size = eoc - ctx->pointer + 1;
-+
-+ /* first subid actually encodes first two subids */
-+ if (size < 2 || size > UINT_MAX/sizeof(unsigned long))
-+ return 0;
-+
-+ *oid = g_try_malloc0_n(size, sizeof(unsigned long));
-+ if (*oid == NULL)
-+ return 0;
-+
-+ optr = *oid;
-+
-+ if (!asn1_subid_decode(ctx, &subid)) {
-+ g_free(*oid);
-+ *oid = NULL;
-+ return 0;
-+ }
-+
-+ if (subid < 40) {
-+ optr[0] = 0;
-+ optr[1] = subid;
-+ } else if (subid < 80) {
-+ optr[0] = 1;
-+ optr[1] = subid - 40;
-+ } else {
-+ optr[0] = 2;
-+ optr[1] = subid - 80;
-+ }
-+
-+ *len = 2;
-+ optr += 2;
-+
-+ while (ctx->pointer < eoc) {
-+ if (++(*len) > size) {
-+ ctx->error = ASN1_ERR_DEC_BADVALUE;
-+ g_free(*oid);
-+ *oid = NULL;
-+ return 0;
-+ }
-+
-+ if (!asn1_subid_decode(ctx, optr++)) {
-+ g_free(*oid);
-+ *oid = NULL;
-+ return 0;
-+ }
-+ }
-+ return 1;
-+}
-+
-+/* return the size of @depth-nested headers + payload */
-+int asn1_header_len(unsigned int payload_len, int depth)
-+{
-+ unsigned int len;
-+ int i;
-+
-+ len = payload_len;
-+ for (i = 0; i < depth; i++) {
-+ /* length */
-+ if (len >= (1 << 24))
-+ len += 5;
-+ else if (len >= (1 << 16))
-+ len += 4;
-+ else if (len >= (1 << 8))
-+ len += 3;
-+ else if (len >= (1 << 7))
-+ len += 2;
-+ else
-+ len += 1;
-+ /* 1-byte header */
-+ len += 1;
-+ }
-+ return len;
-+}
-+
-+int asn1_oid_encode(const unsigned long *in_oid, int in_len,
-+ unsigned char **out_oid, int *out_len)
-+{
-+ unsigned char *oid;
-+ unsigned long id;
-+ int i;
-+
-+ *out_oid = g_try_malloc0_n(in_len, 5);
-+ if (*out_oid == NULL)
-+ return -ENOMEM;
-+
-+ oid = *out_oid;
-+ *oid++ = (unsigned char)(40 * in_oid[0] + in_oid[1]);
-+ for (i = 2; i < in_len; i++) {
-+ id = in_oid[i];
-+ if (id >= (1 << 28))
-+ *oid++ = (0x80 | ((id>>28) & 0x7F));
-+ if (id >= (1 << 21))
-+ *oid++ = (0x80 | ((id>>21) & 0x7F));
-+ if (id >= (1 << 14))
-+ *oid++ = (0x80 | ((id>>14) & 0x7F));
-+ if (id >= (1 << 7))
-+ *oid++ = (0x80 | ((id>>7) & 0x7F));
-+ *oid++ = id & 0x7F;
-+ }
-+ *out_len = (int)(oid - *out_oid);
-+ return 0;
-+}
-+
-+/*
-+ * @len is the sum of all sizes of header, length and payload.
-+ * it will be decreased by the sum of sizes of header and length.
-+ */
-+int asn1_header_encode(unsigned char **buf,
-+ unsigned int cls, unsigned int con, unsigned int tag,
-+ unsigned int *len)
-+{
-+ unsigned char *loc;
-+ unsigned int r_len;
-+
-+ /* at least, 1-byte header + 1-byte length is needed. */
-+ if (*len < 2)
-+ return -EINVAL;
-+
-+ loc = *buf;
-+ r_len = *len;
-+
-+ *loc++ = ((cls & 0x3) << 6) | ((con & 0x1) << 5) | (tag & 0x1F);
-+ r_len -= 1;
-+
-+ if (r_len - 1 < (1 << 7)) {
-+ r_len -= 1;
-+ *loc++ = (unsigned char)(r_len & 0x7F);
-+ } else if (r_len - 2 < (1 << 8)) {
-+ r_len -= 2;
-+ *loc++ = 0x81;
-+ *loc++ = (unsigned char)(r_len & 0xFF);
-+ } else if (r_len - 3 < (1 << 16)) {
-+ r_len -= 3;
-+ *loc++ = 0x82;
-+ *loc++ = (unsigned char)((r_len>>8) & 0xFF);
-+ *loc++ = (unsigned char)(r_len & 0xFF);
-+ } else if (r_len - 4 < (1 << 24)) {
-+ r_len -= 4;
-+ *loc++ = 0x83;
-+ *loc++ = (unsigned char)((r_len>>16) & 0xFF);
-+ *loc++ = (unsigned char)((r_len>>8) & 0xFF);
-+ *loc++ = (unsigned char)(r_len & 0xFF);
-+ } else {
-+ r_len -= 5;
-+ *loc++ = 0x84;
-+ *loc++ = (unsigned char)((r_len>>24) & 0xFF);
-+ *loc++ = (unsigned char)((r_len>>16) & 0xFF);
-+ *loc++ = (unsigned char)((r_len>>8) & 0xFF);
-+ *loc++ = (unsigned char)(r_len & 0xFF);
-+ }
-+
-+ *buf = loc;
-+ *len = r_len;
-+ return 0;
-+}
---- /dev/null
-+++ b/tools/management/spnego_mech.h
-@@ -0,0 +1,48 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later */
-+/*
-+ * Copyright (C) 2020 LG Electronics
-+ *
-+ * linux-cifsd-devel@lists.sourceforge.net
-+ */
-+
-+#ifndef _SPNEGO_MECH_H_
-+#define _SPNEGO_MECH_H_
-+
-+enum {
-+ SPNEGO_MECH_MSKRB5 = 0,
-+ SPNEGO_MECH_KRB5,
-+ SPNEGO_MAX_MECHS,
-+};
-+
-+struct spnego_mech_ctx;
-+
-+typedef int (*spnego_encode_t)(char *in_blob, int in_len,
-+ const unsigned long *oid, int oid_len,
-+ char **out_blob, int *out_len);
-+
-+struct spnego_mech_operations {
-+ int (*setup)(struct spnego_mech_ctx *mech_ctx);
-+ void (*cleanup)(struct spnego_mech_ctx *mech_ctx);
-+ int (*handle_authen)(struct spnego_mech_ctx *mech_ctx,
-+ char *in_blob, unsigned int in_len,
-+ struct ksmbd_spnego_auth_out *auth_out,
-+ spnego_encode_t encode);
-+};
-+
-+struct spnego_mech_ctx {
-+ const unsigned long *oid;
-+ int oid_len;
-+ void *private;
-+ union {
-+ struct {
-+ void *keytab_name;
-+ void *service_name;
-+ } krb5;
-+ } params;
-+ struct spnego_mech_operations *ops;
-+};
-+
-+extern struct spnego_mech_operations spnego_krb5_operations;
-+extern struct spnego_mech_operations spnego_mskrb5_operations;
-+
-+#endif