ksmbd-tools: update to 3.4.7
authorRosen Penev <rosenp@gmail.com>
Wed, 1 Feb 2023 22:58:23 +0000 (14:58 -0800)
committerRosen Penev <rosenp@gmail.com>
Sat, 11 Mar 2023 02:42:02 +0000 (18:42 -0800)
Remove upstreamed patches.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
net/ksmbd-tools/Makefile
net/ksmbd-tools/patches/010-muon.patch [deleted file]
net/ksmbd-tools/patches/020-meson.patch [deleted file]

index 734dcb5419b266b512ac6f9af5fe36e45497e933..1612bd0d2188788240e9f2c6f05a6c7eb6d75848 100644 (file)
@@ -1,12 +1,12 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=ksmbd-tools
-PKG_RELEASE:=$(AUTORELEASE)
+PKG_RELEASE:=1
 
 PKG_SOURCE_PROTO:=git
 PKG_SOURCE_URL:=https://github.com/cifsd-team/ksmbd-tools
-PKG_SOURCE_VERSION:=3.4.6
-PKG_MIRROR_HASH:=c78dace3320cf8a273738b8f3e67bed24c812695f2fab2fbaeae06ec8a15cb77
+PKG_SOURCE_VERSION:=3.4.7
+PKG_MIRROR_HASH:=9128ecac1a2c463e689ed42fd71952a0eafe956f8bcd1b04af58c7bc66a8baee
 
 PKG_LICENSE:=GPL-2.0-or-later
 PKG_LICENSE_FILES:=COPYING
diff --git a/net/ksmbd-tools/patches/010-muon.patch b/net/ksmbd-tools/patches/010-muon.patch
deleted file mode 100644 (file)
index 967c927..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-From 3281f325c820a72057ea639e0d11ad68d5703b43 Mon Sep 17 00:00:00 2001
-From: Rosen Penev <rosenp@gmail.com>
-Date: Thu, 6 Oct 2022 18:07:01 -0700
-Subject: [PATCH] ksmbd-tools: run meson through muon analyze
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Mostly unused variable removals. Removed pointless [] in
-include_directories.
-
-Signed-off-by: Rosen Penev <rosenp@gmail.com>
-Acked-by: Atte Heikkilä <atteh.mailbox@gmail.com>
-Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
----
- addshare/meson.build | 2 +-
- adduser/meson.build  | 2 +-
- control/meson.build  | 2 +-
- meson.build          | 4 ++--
- mountd/meson.build   | 2 +-
- 5 files changed, 6 insertions(+), 6 deletions(-)
-
---- a/addshare/meson.build
-+++ b/addshare/meson.build
-@@ -1,4 +1,4 @@
--addshare = executable(
-+executable(
-   'ksmbd.addshare',
-   'share_admin.c',
-   'addshare.c',
---- a/adduser/meson.build
-+++ b/adduser/meson.build
-@@ -1,4 +1,4 @@
--adduser = executable(
-+executable(
-   'ksmbd.adduser',
-   'md4_hash.c',
-   'user_admin.c',
---- a/control/meson.build
-+++ b/control/meson.build
-@@ -1,4 +1,4 @@
--control = executable(
-+executable(
-   'ksmbd.control',
-   'control.c',
-   dependencies: [
---- a/meson.build
-+++ b/meson.build
-@@ -13,10 +13,10 @@ exec awk '/define KSMBD_TOOLS_VERSION /
-   meson_version: '>= 0.51.0',
- )
--tools_incdir = include_directories([
-+tools_incdir = include_directories(
-   '.',
-   'include',
--])
-+)
- glib_dep = dependency(
-   'glib-2.0',
---- a/mountd/meson.build
-+++ b/mountd/meson.build
-@@ -1,4 +1,4 @@
--mountd = executable(
-+executable(
-   'ksmbd.mountd',
-   'worker.c',
-   'ipc.c',
diff --git a/net/ksmbd-tools/patches/020-meson.patch b/net/ksmbd-tools/patches/020-meson.patch
deleted file mode 100644 (file)
index adc01b6..0000000
+++ /dev/null
@@ -1,9190 +0,0 @@
-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