From: Rosen Penev Date: Wed, 1 Feb 2023 22:58:23 +0000 (-0800) Subject: ksmbd-tools: update to 3.4.7 X-Git-Url: http://git.openwrt.org/?p=feed%2Fpackages.git;a=commitdiff_plain;h=7accad56432cfad8f24768436a8955a9be55f21d ksmbd-tools: update to 3.4.7 Remove upstreamed patches. Signed-off-by: Rosen Penev --- diff --git a/net/ksmbd-tools/Makefile b/net/ksmbd-tools/Makefile index 734dcb5419..1612bd0d21 100644 --- a/net/ksmbd-tools/Makefile +++ b/net/ksmbd-tools/Makefile @@ -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 index 967c92702b..0000000000 --- a/net/ksmbd-tools/patches/010-muon.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 3281f325c820a72057ea639e0d11ad68d5703b43 Mon Sep 17 00:00:00 2001 -From: Rosen Penev -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 -Acked-by: Atte Heikkilä -Signed-off-by: Namjae Jeon ---- - 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 index adc01b655a..0000000000 --- a/net/ksmbd-tools/patches/020-meson.patch +++ /dev/null @@ -1,9190 +0,0 @@ -From 6b74583bd62e2b6ed6b76ff72d8fc7c2d8f26510 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Atte=20Heikkil=C3=A4?= -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ä ---- - .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 - - #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 - - #include --#include -+#include - - #include - ---- 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 - - #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 - - #include --#include -+#include - - #include - #include ---- 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 - #include - --#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 --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --#ifdef HAVE_CONFIG_H --#include --#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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#ifdef HAVE_CONFIG_H -+#include -+#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 - --#include -+#include - #include - #include - #include ---- 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 -+#include - - #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 - #include - #include --#include -+#include - - static GHashTable *pipes_table; - static GRWLock pipes_table_lock; ---- a/mountd/rpc_lsarpc.c -+++ b/mountd/rpc_lsarpc.c -@@ -16,7 +16,7 @@ - #include - #include - #include --#include -+#include - - #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 - #include - #include --#include -+#include - - #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 - #include --#include -+#include - - #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 - #include --#include -+#include - - #define WKSSVC_NETWKSTA_GET_INFO (0) - ---- a/mountd/smbacl.c -+++ b/mountd/smbacl.c -@@ -7,7 +7,7 @@ - */ - - #include --#include -+#include - #include - - 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 - #include - --#include -+#include - #include - #include - #include ---- 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 --#include --#include --#include --#include --#include --#include --#include -- --#include --#include --#include --#include -- --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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+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 --#include --#include -- --#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 -+#include -+#include -+ -+#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 --#include --#include --#include --#include --#include -- --#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 -+#include -+#include -+#include -+#include -+#include -+ -+#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 --#include --#include --#include --#include --#include --#include -- --#include --#include --#include --#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 -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#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 --#include --#include --#include --#include --#include --#include -- --#include --#include --#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 [/[@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 -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#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 [/[@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 --#include --#include -- --#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 -+#include -+#include -+ -+#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 --#include --#include -- --#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 -+#include -+#include -+ -+#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 -- --#include --#include --#include -- --#include --#include -- --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 -+ -+#include -+#include -+#include -+ -+#include -+#include -+ -+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 --#include --#include --#include --#include -- --#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 -+#include -+#include -+#include -+#include -+ -+#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