├── autogen.sh ├── PFIF.txt ├── include ├── version.h ├── worker.h ├── rpc_srvsvc.h ├── rpc_wkssvc.h ├── rpc_samr.h ├── management │ ├── session.h │ ├── spnego.h │ ├── tree_conn.h │ ├── user.h │ └── share.h ├── rpc_lsarpc.h ├── ipc.h ├── config_parser.h ├── smbacl.h ├── asn1.h ├── tools.h └── linux │ └── ksmbd_server.h ├── ksmbd.service.in ├── addshare ├── share_admin.h ├── Makefile.am ├── meson.build ├── ksmbd.addshare.8.in └── addshare.c ├── adduser ├── user_admin.h ├── Makefile.am ├── meson.build ├── md4_hash.h ├── ksmbd.adduser.8.in ├── adduser.c ├── md4_hash.c └── user_admin.c ├── meson_options.txt ├── control ├── Makefile.am ├── meson.build ├── ksmbd.control.8.in └── control.c ├── Makefile.am ├── mountd ├── Makefile.am ├── meson.build ├── ksmbd.mountd.8.in ├── rpc_wkssvc.c ├── smbacl.c ├── worker.c └── mountd.c ├── tools ├── meson.build ├── Makefile.am ├── management │ ├── spnego_mech.h │ ├── session.c │ ├── tree_conn.c │ ├── spnego.c │ └── user.c ├── tools.c └── asn1.c ├── AUTHORS ├── .gitignore ├── ksmbd.conf.example ├── ksmbdpwd.db.5.in ├── .travis.yml ├── ksmbd-tools.spec ├── .github └── workflows │ └── c-cpp.yml ├── meson.build ├── configure.ac └── README.md /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | autoreconf --install --verbose 4 | -------------------------------------------------------------------------------- /PFIF.txt: -------------------------------------------------------------------------------- 1 | This code was developed in participation with the Protocol Freedom 2 | Information Foundation. 3 | 4 | Please see 5 | http://protocolfreedom.org/ and 6 | http://samba.org/samba/PFIF/ 7 | for more details. 8 | -------------------------------------------------------------------------------- /include/version.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /* 3 | * Copyright (C) 2020 Namjae Jeon 4 | */ 5 | 6 | #ifndef _VERSION_H 7 | 8 | #define KSMBD_TOOLS_VERSION "3.5.6" 9 | 10 | #endif /* !_VERSION_H */ 11 | -------------------------------------------------------------------------------- /include/worker.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /* 3 | * Copyright (C) 2018 Samsung Electronics Co., Ltd. 4 | * 5 | * linux-cifsd-devel@lists.sourceforge.net 6 | */ 7 | 8 | #ifndef __KSMBD_WORKER__H__ 9 | #define __KSMBD_WORKER__H__ 10 | 11 | struct ksmbd_ipc_msg; 12 | 13 | int wp_ipc_msg_push(struct ksmbd_ipc_msg *msg); 14 | void wp_destroy(void); 15 | void wp_init(void); 16 | 17 | #endif /* __KSMBD_WORKER_H__ */ 18 | -------------------------------------------------------------------------------- /ksmbd.service.in: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=ksmbd userspace daemon 3 | Requires=modprobe@ksmbd.service 4 | Wants=network-online.target 5 | After=modprobe@ksmbd.service network.target network-online.target 6 | 7 | [Service] 8 | Type=forking 9 | PIDFile=@runstatedir@/ksmbd.lock 10 | ExecStart=@sbindir@/ksmbd.mountd 11 | ExecReload=@sbindir@/ksmbd.control --reload 12 | ExecStop=@sbindir@/ksmbd.control --shutdown 13 | 14 | [Install] 15 | WantedBy=multi-user.target 16 | -------------------------------------------------------------------------------- /addshare/share_admin.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /* 3 | * Copyright (C) 2019 Samsung Electronics Co., Ltd. 4 | * 5 | * linux-cifsd-devel@lists.sourceforge.net 6 | */ 7 | 8 | #ifndef __KSMBD_SHARE_ADMIN_H__ 9 | #define __KSMBD_SHARE_ADMIN_H__ 10 | 11 | typedef int command_fn(char *smbconf, char *name, char **options); 12 | 13 | command_fn command_add_share, command_update_share, command_delete_share; 14 | 15 | #endif /* __KSMBD_SHARE_ADMIN_H__ */ 16 | -------------------------------------------------------------------------------- /adduser/user_admin.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /* 3 | * Copyright (C) 2018 Samsung Electronics Co., Ltd. 4 | * 5 | * linux-cifsd-devel@lists.sourceforge.net 6 | */ 7 | 8 | #ifndef __KSMBD_USER_ADMIN_H__ 9 | #define __KSMBD_USER_ADMIN_H__ 10 | 11 | #define MAX_NT_PWD_LEN 129 12 | 13 | typedef int command_fn(char *pwddb, char *name, char *password); 14 | 15 | command_fn command_add_user, command_update_user, command_delete_user; 16 | 17 | #endif /* __KSMBD_USER_ADMIN_H__ */ 18 | -------------------------------------------------------------------------------- /include/rpc_srvsvc.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /* 3 | * Copyright (C) 2018 Samsung Electronics Co., Ltd. 4 | * 5 | * linux-cifsd-devel@lists.sourceforge.net 6 | */ 7 | 8 | #ifndef __KSMBD_RPC_SRVSVC_H__ 9 | #define __KSMBD_RPC_SRVSVC_H__ 10 | 11 | struct ksmbd_rpc_command; 12 | struct ksmbd_rpc_pipe; 13 | 14 | int rpc_srvsvc_read_request(struct ksmbd_rpc_pipe *pipe, 15 | struct ksmbd_rpc_command *resp, 16 | int max_resp_sz); 17 | 18 | int rpc_srvsvc_write_request(struct ksmbd_rpc_pipe *pipe); 19 | 20 | #endif /* __KSMBD_RPC_SRVSVC_H__ */ 21 | -------------------------------------------------------------------------------- /include/rpc_wkssvc.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /* 3 | * Copyright (C) 2018 Samsung Electronics Co., Ltd. 4 | * 5 | * linux-cifsd-devel@lists.sourceforge.net 6 | */ 7 | 8 | #ifndef __KSMBD_RPC_WKSSVC_H__ 9 | #define __KSMBD_RPC_WKSSVC_H__ 10 | 11 | struct ksmbd_rpc_command; 12 | struct ksmbd_rpc_pipe; 13 | 14 | int rpc_wkssvc_read_request(struct ksmbd_rpc_pipe *pipe, 15 | struct ksmbd_rpc_command *resp, 16 | int max_resp_sz); 17 | 18 | int rpc_wkssvc_write_request(struct ksmbd_rpc_pipe *pipe); 19 | 20 | #endif /* __KSMBD_RPC_WKSSVC_H__ */ 21 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option( 2 | 'rundir', 3 | type: 'string', 4 | description: 'Directory to store modifiable per-process data (LOCALSTATEDIR/run by default)', 5 | ) 6 | 7 | option( 8 | 'systemdsystemunitdir', 9 | type: 'string', 10 | description: 'Directory to install systemd unit file (query pkg-config by default)', 11 | ) 12 | 13 | option( 14 | 'krb5', 15 | type: 'feature', 16 | value: 'disabled', 17 | description: 'Support for Kerberos 5 authentication', 18 | ) 19 | 20 | option( 21 | 'krb5_name', 22 | type: 'string', 23 | value: 'krb5', 24 | description: 'Dependency name used when checking Kerberos 5 support', 25 | ) 26 | -------------------------------------------------------------------------------- /control/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CFLAGS = -DSYSCONFDIR='"${sysconfdir}"' -DRUNSTATEDIR='"${runstatedir}"' \ 2 | -I$(top_srcdir)/include $(GLIB_CFLAGS) $(LIBNL_CFLAGS) -fno-common 3 | 4 | noinst_LIBRARIES = libcontrol.a 5 | libcontrol_a_SOURCES = control.c 6 | 7 | EXTRA_DIST = ksmbd.control.8.in \ 8 | meson.build 9 | 10 | man_MANS = ksmbd.control.8 11 | $(man_MANS): %: %.in; @$(in_script) $< >$@ 12 | 13 | CLEANFILES = $(man_MANS) 14 | 15 | install-exec-hook: uninstall-hook 16 | $(MKDIR_P) $(DESTDIR)$(sbindir) 17 | ( cd $(DESTDIR)$(sbindir) && \ 18 | $(LN_S) $(libexecdir)/ksmbd.tools ksmbd.control ) 19 | 20 | uninstall-hook: 21 | -rm $(DESTDIR)$(sbindir)/ksmbd.control 22 | -------------------------------------------------------------------------------- /control/meson.build: -------------------------------------------------------------------------------- 1 | control_lib = static_library( 2 | 'control', 3 | 'control.c', 4 | include_directories: include_dirs, 5 | c_args: [ 6 | '-DSYSCONFDIR="@0@"'.format(get_option('prefix') / get_option('sysconfdir')), 7 | '-DRUNSTATEDIR="@0@"'.format(runstatedir), 8 | ], 9 | dependencies: [ 10 | glib_dep, 11 | ], 12 | ) 13 | 14 | configure_file( 15 | input: 'ksmbd.control.8.in', 16 | output: 'ksmbd.control.8', 17 | install_dir: get_option('mandir') / 'man8', 18 | configuration: in_data, 19 | ) 20 | 21 | install_symlink( 22 | 'ksmbd.control', 23 | install_dir: get_option('sbindir'), 24 | pointing_to: get_option('prefix') / get_option('libexecdir') / 'ksmbd.tools', 25 | ) 26 | -------------------------------------------------------------------------------- /addshare/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CFLAGS = -DSYSCONFDIR='"${sysconfdir}"' -DRUNSTATEDIR='"${runstatedir}"' \ 2 | -I$(top_srcdir)/include $(GLIB_CFLAGS) $(LIBNL_CFLAGS) -fno-common 3 | 4 | noinst_LIBRARIES = libaddshare.a 5 | libaddshare_a_SOURCES = share_admin.c addshare.c share_admin.h 6 | 7 | EXTRA_DIST = ksmbd.addshare.8.in \ 8 | meson.build 9 | 10 | man_MANS = ksmbd.addshare.8 11 | $(man_MANS): %: %.in; @$(in_script) $< >$@ 12 | 13 | CLEANFILES = $(man_MANS) 14 | 15 | install-exec-hook: uninstall-hook 16 | $(MKDIR_P) $(DESTDIR)$(sbindir) 17 | ( cd $(DESTDIR)$(sbindir) && \ 18 | $(LN_S) $(libexecdir)/ksmbd.tools ksmbd.addshare ) 19 | 20 | uninstall-hook: 21 | -rm $(DESTDIR)$(sbindir)/ksmbd.addshare 22 | -------------------------------------------------------------------------------- /adduser/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CFLAGS = -DSYSCONFDIR='"${sysconfdir}"' -DRUNSTATEDIR='"${runstatedir}"' \ 2 | -I$(top_srcdir)/include $(GLIB_CFLAGS) $(LIBNL_CFLAGS) -fno-common 3 | 4 | noinst_LIBRARIES = libadduser.a 5 | libadduser_a_SOURCES = md4_hash.c user_admin.c adduser.c md4_hash.h user_admin.h 6 | 7 | EXTRA_DIST = ksmbd.adduser.8.in \ 8 | meson.build 9 | 10 | man_MANS = ksmbd.adduser.8 11 | $(man_MANS): %: %.in; @$(in_script) $< >$@ 12 | 13 | CLEANFILES = $(man_MANS) 14 | 15 | install-exec-hook: uninstall-hook 16 | $(MKDIR_P) $(DESTDIR)$(sbindir) 17 | ( cd $(DESTDIR)$(sbindir) && \ 18 | $(LN_S) $(libexecdir)/ksmbd.tools ksmbd.adduser ) 19 | 20 | uninstall-hook: 21 | -rm $(DESTDIR)$(sbindir)/ksmbd.adduser 22 | -------------------------------------------------------------------------------- /addshare/meson.build: -------------------------------------------------------------------------------- 1 | addshare_lib = static_library( 2 | 'addshare', 3 | 'share_admin.c', 4 | 'addshare.c', 5 | 'share_admin.h', 6 | include_directories: include_dirs, 7 | c_args: [ 8 | '-DSYSCONFDIR="@0@"'.format(get_option('prefix') / get_option('sysconfdir')), 9 | '-DRUNSTATEDIR="@0@"'.format(runstatedir), 10 | ], 11 | dependencies: [ 12 | glib_dep, 13 | ], 14 | ) 15 | 16 | configure_file( 17 | input: 'ksmbd.addshare.8.in', 18 | output: 'ksmbd.addshare.8', 19 | install_dir: get_option('mandir') / 'man8', 20 | configuration: in_data, 21 | ) 22 | 23 | install_symlink( 24 | 'ksmbd.addshare', 25 | install_dir: get_option('sbindir'), 26 | pointing_to: get_option('prefix') / get_option('libexecdir') / 'ksmbd.tools', 27 | ) 28 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I m4 2 | 3 | SUBDIRS = addshare adduser control mountd tools 4 | 5 | EXTRA_DIST = include \ 6 | README.md \ 7 | ksmbd-tools.spec \ 8 | ksmbd.conf.5.in \ 9 | ksmbdpwd.db.5.in \ 10 | ksmbd.service.in \ 11 | meson.build \ 12 | meson_options.txt 13 | 14 | pkgsysconfdir = $(sysconfdir)/ksmbd 15 | dist_pkgsysconf_DATA = ksmbd.conf.example 16 | 17 | man_MANS = ksmbd.conf.5 ksmbdpwd.db.5 18 | systemdsystemunit_DATA = ksmbd.service 19 | $(man_MANS) $(systemdsystemunit_DATA): %: %.in; @$(in_script) $< >$@ 20 | 21 | CLEANFILES = $(man_MANS) $(systemdsystemunit_DATA) 22 | 23 | AM_DISTCHECK_CONFIGURE_FLAGS = \ 24 | --with-systemdsystemunitdir=$${dc_install_base}/$(systemdsystemunitdir) 25 | -------------------------------------------------------------------------------- /mountd/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CFLAGS = -DSYSCONFDIR='"${sysconfdir}"' -DRUNSTATEDIR='"${runstatedir}"' \ 2 | -I$(top_srcdir)/include $(GLIB_CFLAGS) $(LIBNL_CFLAGS) -fno-common 3 | 4 | noinst_LIBRARIES = libmountd.a 5 | libmountd_a_SOURCES = worker.c ipc.c rpc.c rpc_srvsvc.c rpc_wkssvc.c mountd.c \ 6 | smbacl.c rpc_samr.c rpc_lsarpc.c 7 | 8 | EXTRA_DIST = ksmbd.mountd.8.in \ 9 | meson.build 10 | 11 | man_MANS = ksmbd.mountd.8 12 | $(man_MANS): %: %.in; @$(in_script) $< >$@ 13 | 14 | CLEANFILES = $(man_MANS) 15 | 16 | install-exec-hook: uninstall-hook 17 | $(MKDIR_P) $(DESTDIR)$(sbindir) 18 | ( cd $(DESTDIR)$(sbindir) && \ 19 | $(LN_S) $(libexecdir)/ksmbd.tools ksmbd.mountd ) 20 | 21 | uninstall-hook: 22 | -rm $(DESTDIR)$(sbindir)/ksmbd.mountd 23 | -------------------------------------------------------------------------------- /adduser/meson.build: -------------------------------------------------------------------------------- 1 | adduser_lib = static_library( 2 | 'adduser', 3 | 'md4_hash.c', 4 | 'user_admin.c', 5 | 'adduser.c', 6 | 'md4_hash.h', 7 | 'user_admin.h', 8 | include_directories: include_dirs, 9 | c_args: [ 10 | '-DSYSCONFDIR="@0@"'.format(get_option('prefix') / get_option('sysconfdir')), 11 | '-DRUNSTATEDIR="@0@"'.format(runstatedir), 12 | ], 13 | dependencies: [ 14 | glib_dep, 15 | ], 16 | ) 17 | 18 | configure_file( 19 | input: 'ksmbd.adduser.8.in', 20 | output: 'ksmbd.adduser.8', 21 | install_dir: get_option('mandir') / 'man8', 22 | configuration: in_data, 23 | ) 24 | 25 | install_symlink( 26 | 'ksmbd.adduser', 27 | install_dir: get_option('sbindir'), 28 | pointing_to: get_option('prefix') / get_option('libexecdir') / 'ksmbd.tools', 29 | ) 30 | -------------------------------------------------------------------------------- /include/rpc_samr.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /* 3 | * Copyright (C) 2020 Samsung Electronics Co., Ltd. 4 | * 5 | * Author(s): Namjae Jeon (linkinjeon@kernel.org) 6 | */ 7 | 8 | #ifndef __KSMBD_RPC_SAMR_H__ 9 | #define __KSMBD_RPC_SAMR_H__ 10 | 11 | #include 12 | 13 | #define HANDLE_SIZE 20 14 | 15 | struct ksmbd_rpc_command; 16 | struct ksmbd_rpc_pipe; 17 | 18 | struct connect_handle { 19 | unsigned char handle[HANDLE_SIZE]; 20 | unsigned int refcount; 21 | struct ksmbd_user *user; 22 | }; 23 | 24 | int rpc_samr_read_request(struct ksmbd_rpc_pipe *pipe, 25 | struct ksmbd_rpc_command *resp, 26 | int max_resp_sz); 27 | 28 | int rpc_samr_write_request(struct ksmbd_rpc_pipe *pipe); 29 | 30 | void rpc_samr_init(void); 31 | void rpc_samr_destroy(void); 32 | #endif /* __KSMBD_RPC_SAMR_H__ */ 33 | -------------------------------------------------------------------------------- /mountd/meson.build: -------------------------------------------------------------------------------- 1 | mountd_lib = static_library( 2 | 'mountd', 3 | 'worker.c', 4 | 'ipc.c', 5 | 'rpc.c', 6 | 'rpc_srvsvc.c', 7 | 'rpc_wkssvc.c', 8 | 'mountd.c', 9 | 'smbacl.c', 10 | 'rpc_samr.c', 11 | 'rpc_lsarpc.c', 12 | include_directories: include_dirs, 13 | c_args: [ 14 | '-DSYSCONFDIR="@0@"'.format(get_option('prefix') / get_option('sysconfdir')), 15 | '-DRUNSTATEDIR="@0@"'.format(runstatedir), 16 | ], 17 | dependencies: [ 18 | glib_dep, 19 | libnl_dep, 20 | ], 21 | ) 22 | 23 | configure_file( 24 | input: 'ksmbd.mountd.8.in', 25 | output: 'ksmbd.mountd.8', 26 | install_dir: get_option('mandir') / 'man8', 27 | configuration: in_data, 28 | ) 29 | 30 | install_symlink( 31 | 'ksmbd.mountd', 32 | install_dir: get_option('sbindir'), 33 | pointing_to: get_option('prefix') / get_option('libexecdir') / 'ksmbd.tools', 34 | ) 35 | -------------------------------------------------------------------------------- /tools/meson.build: -------------------------------------------------------------------------------- 1 | ksmbd_tools_files = [ 2 | 'management/tree_conn.c', 3 | 'management/user.c', 4 | 'management/share.c', 5 | 'management/session.c', 6 | 'config_parser.c', 7 | 'tools.c', 8 | ] 9 | 10 | if krb5_dep.found() 11 | ksmbd_tools_files += [ 12 | 'management/spnego.c', 13 | 'asn1.c', 14 | 'management/spnego_krb5.c', 15 | ] 16 | endif 17 | 18 | executable( 19 | 'ksmbd.tools', 20 | ksmbd_tools_files, 21 | include_directories: include_dirs, 22 | c_args: [ 23 | '-DSYSCONFDIR="@0@"'.format(get_option('prefix') / get_option('sysconfdir')), 24 | '-DRUNSTATEDIR="@0@"'.format(runstatedir), 25 | ], 26 | dependencies: [ 27 | glib_dep, 28 | krb5_dep, 29 | asn1_lib, 30 | pthread_lib, 31 | ], 32 | link_with: [ 33 | addshare_lib, 34 | adduser_lib, 35 | control_lib, 36 | mountd_lib, 37 | ], 38 | install: true, 39 | install_dir: get_option('libexecdir'), 40 | ) 41 | -------------------------------------------------------------------------------- /include/management/session.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /* 3 | * Copyright (C) 2018 Samsung Electronics Co., Ltd. 4 | * 5 | * linux-cifsd-devel@lists.sourceforge.net 6 | */ 7 | 8 | #ifndef __MANAGEMENT_TCONNECTION_H__ 9 | #define __MANAGEMENT_TCONNECTION_H__ 10 | 11 | #include 12 | 13 | struct ksmbd_user; 14 | 15 | struct ksmbd_session { 16 | unsigned long long id; 17 | 18 | struct ksmbd_user *user; 19 | 20 | GRWLock update_lock; 21 | GList *tree_conns; 22 | int ref_counter; 23 | }; 24 | 25 | struct ksmbd_tree_conn; 26 | 27 | int sm_check_sessions_capacity(unsigned long long id); 28 | 29 | int sm_handle_tree_connect(unsigned long long id, 30 | struct ksmbd_user *user, 31 | struct ksmbd_tree_conn *tree_conn); 32 | int sm_handle_tree_disconnect(unsigned long long sess_id, 33 | unsigned long long tree_conn_id); 34 | 35 | void sm_destroy(void); 36 | void sm_init(void); 37 | 38 | #endif /* __MANAGEMENT_TCONNECTION_H__ */ 39 | -------------------------------------------------------------------------------- /include/management/spnego.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /* 3 | * Copyright (C) 2020 LG Electronics 4 | * 5 | * linux-cifsd-devel@lists.sourceforge.net 6 | */ 7 | 8 | #ifndef _MANAGEMENT_SPNEGO_H_ 9 | #define _MANAGEMENT_SPNEGO_H_ 10 | 11 | struct ksmbd_spnego_auth_out { 12 | char *spnego_blob; 13 | unsigned int blob_len; 14 | char *sess_key; 15 | unsigned int key_len; 16 | char *user_name; 17 | }; 18 | 19 | struct ksmbd_spnego_authen_request; 20 | 21 | #ifdef CONFIG_KRB5 22 | void spnego_init(void); 23 | void spnego_destroy(void); 24 | int spnego_handle_authen_request(struct ksmbd_spnego_authen_request *req, 25 | struct ksmbd_spnego_auth_out *auth_out); 26 | #else 27 | static inline void spnego_init(void) {} 28 | static inline void spnego_destroy(void) {} 29 | static inline int spnego_handle_authen_request(struct ksmbd_spnego_authen_request *req, 30 | struct ksmbd_spnego_auth_out *auth_out) 31 | { 32 | return -ENOTSUP; 33 | } 34 | #endif 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /include/rpc_lsarpc.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /* 3 | * Copyright (C) 2020 Samsung Electronics Co., Ltd. 4 | * 5 | * Author(s): Namjae Jeon (linkinjeon@kernel.org) 6 | */ 7 | 8 | #ifndef __KSMBD_RPC_LSARPC_H__ 9 | #define __KSMBD_RPC_LSARPC_H__ 10 | 11 | #include 12 | 13 | #define HANDLE_SIZE 20 14 | #define DOMAIN_STR_SIZE 257 15 | 16 | struct ksmbd_rpc_command; 17 | struct ksmbd_rpc_pipe; 18 | 19 | struct policy_handle { 20 | unsigned char handle[HANDLE_SIZE]; 21 | struct ksmbd_user *user; 22 | }; 23 | 24 | struct lsarpc_names_info { 25 | unsigned int index; 26 | int type; 27 | char domain_str[DOMAIN_STR_SIZE]; 28 | struct smb_sid sid; 29 | struct ksmbd_user *user; 30 | }; 31 | 32 | int rpc_lsarpc_read_request(struct ksmbd_rpc_pipe *pipe, 33 | struct ksmbd_rpc_command *resp, 34 | int max_resp_sz); 35 | 36 | int rpc_lsarpc_write_request(struct ksmbd_rpc_pipe *pipe); 37 | void rpc_lsarpc_init(void); 38 | void rpc_lsarpc_destroy(void); 39 | 40 | #endif /* __KSMBD_RPC_LSARPC_H__ */ 41 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Original Author and Creator 2 | =========================== 3 | Namjae Jeon 4 | 5 | Maintainers 6 | =============== 7 | Namjae Jeon 8 | 9 | Patch Contributors and Developers 10 | --------------------------------- 11 | Atte Heikkilä 12 | Marios Makassikis 13 | Rosen Penev 14 | Sergey Senozhatsky (Resolve overall architecture issues and make close to the mainline. and his work cause ksmbd 2.0 to be reborn) 15 | Taeyang Mok (various ksmbd works) 16 | Yunjae Lim (compatibility works for several windows version and MS-SMB2 testsuite) 17 | Hyunchul Lee (SMBDirect works) 18 | Gibeom Kim 19 | Pankaj Sharma 20 | Anupam Aggarwal 21 | Mayank Singh 22 | kumar sourav 23 | Vivek Trivedi 24 | Amit Sahrawat 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # automake 2 | 3 | Makefile.in 4 | /ar-lib 5 | /mdate-sh 6 | /py-compile 7 | /test-driver 8 | /ylwrap 9 | .deps/ 10 | .dirstamp 11 | 12 | # autoconf 13 | 14 | autom4te.cache 15 | build-aux 16 | /autoscan.log 17 | /autoscan-*.log 18 | /aclocal.m4 19 | /compile 20 | /config.cache 21 | /config.guess 22 | /config.h.in 23 | /config.h 24 | /config.log 25 | /config.status 26 | /config.sub 27 | /configure 28 | /configure.scan 29 | /depcomp 30 | /install-sh 31 | /missing 32 | /stamp-h1 33 | 34 | # libtool 35 | 36 | /libtool 37 | /ltmain.sh 38 | 39 | # texinfo 40 | 41 | /texinfo.tex 42 | 43 | # m4 44 | 45 | m4/libtool.m4 46 | m4/ltoptions.m4 47 | m4/ltsugar.m4 48 | m4/ltversion.m4 49 | m4/lt~obsolete.m4 50 | 51 | # Generated by autotools 52 | Makefile 53 | 54 | # Prerequisites 55 | *.d 56 | 57 | # Object files 58 | *.o 59 | *.ko 60 | *.obj 61 | *.elf 62 | 63 | # Linker output 64 | *.ilk 65 | *.map 66 | *.exp 67 | 68 | # Precompiled Headers 69 | *.gch 70 | *.pch 71 | 72 | # Libraries 73 | *.lib 74 | *.a 75 | *.la 76 | *.lo 77 | 78 | # Executables 79 | ksmbd.* 80 | ksmbdctl 81 | -------------------------------------------------------------------------------- /tools/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CFLAGS = -DSYSCONFDIR='"${sysconfdir}"' -DRUNSTATEDIR='"${runstatedir}"' \ 2 | -I$(top_srcdir)/include $(GLIB_CFLAGS) $(LIBKRB5_CFLAGS) -fno-common 3 | LIBS = $(GLIB_LIBS) $(LIBNL_LIBS) $(LIBKRB5_LIBS) $(PTHREAD_LIBS) 4 | 5 | EXTRA_DIST = meson.build 6 | 7 | libexec_PROGRAMS = ksmbd.tools 8 | ksmbd_tools_SOURCES = management/tree_conn.c \ 9 | management/user.c \ 10 | management/share.c \ 11 | management/session.c \ 12 | config_parser.c \ 13 | tools.c 14 | if HAVE_LIBKRB5 15 | ksmbd_tools_SOURCES += management/spnego.c \ 16 | asn1.c \ 17 | management/spnego_krb5.c \ 18 | management/spnego_mech.h 19 | endif 20 | ksmbd_tools_LDADD = $(top_builddir)/addshare/libaddshare.a \ 21 | $(top_builddir)/adduser/libadduser.a \ 22 | $(top_builddir)/control/libcontrol.a \ 23 | $(top_builddir)/mountd/libmountd.a 24 | -------------------------------------------------------------------------------- /include/ipc.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /* 3 | * Copyright (C) 2018 Samsung Electronics Co., Ltd. 4 | * 5 | * linux-cifsd-devel@lists.sourceforge.net 6 | */ 7 | 8 | #ifndef __KSMBD_IPC_H__ 9 | #define __KSMBD_IPC_H__ 10 | 11 | /* 12 | * Older [prior to 4.9] kernels had max NL recv msg size of 16k. 13 | * It has been bumped to 32K later on. 14 | */ 15 | #define KSMBD_IPC_MAX_MESSAGE_SIZE (16 * 1024) 16 | 17 | /* 18 | * The netlink socket's receive buffer size needs to be increased 19 | * to avoid -ENOBUFS errors when receiving. 20 | */ 21 | #define KSMBD_IPC_SO_RCVBUF_SIZE (1 * 1024 * 1024) 22 | 23 | struct ksmbd_ipc_msg { 24 | unsigned int type; 25 | unsigned int sz; 26 | unsigned char ____payload[0]; 27 | }; 28 | 29 | #define KSMBD_IPC_MSG_PAYLOAD(m) \ 30 | (void *)(((struct ksmbd_ipc_msg *)(m))->____payload) 31 | 32 | struct ksmbd_ipc_msg *ipc_msg_alloc(size_t sz); 33 | void ipc_msg_free(struct ksmbd_ipc_msg *msg); 34 | 35 | int ipc_msg_send(struct ksmbd_ipc_msg *msg); 36 | 37 | int ipc_process_event(void); 38 | void ipc_destroy(void); 39 | void ipc_init(void); 40 | 41 | #endif /* __KSMBD_IPC_H__ */ 42 | -------------------------------------------------------------------------------- /adduser/md4_hash.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /* 3 | * Cryptographic API. 4 | * 5 | * MD4 Message Digest Algorithm (RFC1320). 6 | * 7 | * Implementation derived from Andrew Tridgell and Steve French's 8 | * CIFS MD4 implementation, and the cryptoapi implementation 9 | * originally based on the public domain implementation written 10 | * by Colin Plumb in 1993. 11 | * 12 | * Copyright (c) Andrew Tridgell 1997-1998. 13 | * Modified by Steve French (sfrench@us.ibm.com) 2002 14 | * Modified by Namjae Jeon (namjae.jeon@samsung.com) 2015 15 | * Copyright (c) Cryptoapi developers. 16 | * Copyright (c) 2002 David S. Miller (davem@redhat.com) 17 | * Copyright (c) 2002 James Morris 18 | */ 19 | 20 | #ifndef __MD4_HASH_H__ 21 | #define __MD4_HASH_H__ 22 | 23 | #define MD4_BLOCK_WORDS 16 24 | #define MD4_HASH_WORDS 4 25 | 26 | struct md4_ctx { 27 | unsigned int hash[MD4_HASH_WORDS]; 28 | unsigned int block[MD4_BLOCK_WORDS]; 29 | unsigned long long byte_count; 30 | }; 31 | 32 | void md4_init(struct md4_ctx *mctx); 33 | void md4_update(struct md4_ctx *mctx, const unsigned char *data, 34 | unsigned int len); 35 | void md4_final(struct md4_ctx *mctx, unsigned char *out); 36 | 37 | #endif /* __MD4_HASH_H__ */ 38 | -------------------------------------------------------------------------------- /include/management/tree_conn.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /* 3 | * Copyright (C) 2018 Samsung Electronics Co., Ltd. 4 | * 5 | * linux-cifsd-devel@lists.sourceforge.net 6 | */ 7 | 8 | #ifndef __MANAGEMENT_TREE_CONN_H__ 9 | #define __MANAGEMENT_TREE_CONN_H__ 10 | 11 | #include 12 | 13 | struct ksmbd_share; 14 | 15 | struct ksmbd_tree_conn { 16 | unsigned long long id; 17 | 18 | struct ksmbd_share *share; 19 | unsigned int flags; 20 | }; 21 | 22 | static inline void set_conn_flag(struct ksmbd_tree_conn *conn, int bit) 23 | { 24 | conn->flags |= bit; 25 | } 26 | 27 | static inline void clear_conn_flag(struct ksmbd_tree_conn *conn, int bit) 28 | { 29 | conn->flags &= ~bit; 30 | } 31 | 32 | static inline int test_conn_flag(struct ksmbd_tree_conn *conn, int bit) 33 | { 34 | return conn->flags & bit; 35 | } 36 | 37 | void tcm_tree_conn_free(struct ksmbd_tree_conn *conn); 38 | 39 | struct ksmbd_tree_connect_request; 40 | struct ksmbd_tree_connect_response; 41 | 42 | int tcm_handle_tree_connect(struct ksmbd_tree_connect_request *req, 43 | struct ksmbd_tree_connect_response *resp); 44 | 45 | int tcm_handle_tree_disconnect(unsigned long long sess_id, 46 | unsigned long long tree_conn_id); 47 | #endif /* __MANAGEMENT_TREE_CONN_H__ */ 48 | -------------------------------------------------------------------------------- /tools/management/spnego_mech.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /* 3 | * Copyright (C) 2020 LG Electronics 4 | * 5 | * linux-cifsd-devel@lists.sourceforge.net 6 | */ 7 | 8 | #ifndef _SPNEGO_MECH_H_ 9 | #define _SPNEGO_MECH_H_ 10 | 11 | enum { 12 | SPNEGO_MECH_MSKRB5 = 0, 13 | SPNEGO_MECH_KRB5, 14 | SPNEGO_MAX_MECHS, 15 | }; 16 | 17 | struct spnego_mech_ctx; 18 | 19 | typedef int (*spnego_encode_t)(char *in_blob, int in_len, 20 | const unsigned long *oid, int oid_len, 21 | char **out_blob, int *out_len); 22 | 23 | struct spnego_mech_operations { 24 | int (*setup)(struct spnego_mech_ctx *mech_ctx); 25 | void (*cleanup)(struct spnego_mech_ctx *mech_ctx); 26 | int (*handle_authen)(struct spnego_mech_ctx *mech_ctx, 27 | char *in_blob, unsigned int in_len, 28 | struct ksmbd_spnego_auth_out *auth_out, 29 | spnego_encode_t encode); 30 | }; 31 | 32 | struct spnego_mech_ctx { 33 | const unsigned long *oid; 34 | int oid_len; 35 | void *private; 36 | union { 37 | struct { 38 | void *keytab_name; 39 | void *service_name; 40 | } krb5; 41 | } params; 42 | struct spnego_mech_operations *ops; 43 | }; 44 | 45 | extern struct spnego_mech_operations spnego_krb5_operations; 46 | extern struct spnego_mech_operations spnego_mskrb5_operations; 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /ksmbd.conf.example: -------------------------------------------------------------------------------- 1 | ; see ksmbd.conf(5) for details 2 | 3 | [global] 4 | ; global parameters 5 | bind interfaces only = no 6 | deadtime = 0 7 | durable handles = no 8 | guest account = nobody 9 | interfaces = 10 | ipc timeout = 0 11 | kerberos keytab file = 12 | kerberos service name = 13 | kerberos support = no 14 | map to guest = never 15 | max active sessions = 1024 16 | max connections = 128 17 | max ip connections = 8 18 | max open files = 10000 19 | netbios name = KSMBD SERVER 20 | restrict anonymous = 0 21 | root directory = 22 | server max protocol = SMB3_11 23 | server min protocol = SMB2_10 24 | server multi channel support = no 25 | server signing = auto 26 | server string = SMB SERVER 27 | share:fake_fscaps = 64 28 | smb2 leases = no 29 | smb2 max credits = 8192 30 | smb2 max read = 4MB 31 | smb2 max trans = 1MB 32 | smb2 max write = 4MB 33 | smb3 encryption = auto 34 | smbd max io size = 8MB 35 | tcp port = 445 36 | workgroup = WORKGROUP 37 | 38 | ; default share parameters 39 | browseable = yes 40 | comment = 41 | create mask = 0744 42 | crossmnt = yes 43 | directory mask = 0755 44 | follow symlinks = no 45 | force create mode = 0000 46 | force directory mode = 0000 47 | force group = 48 | force user = 49 | guest ok = no 50 | hide dot files = yes 51 | inherit owner = no 52 | invalid users = 53 | oplocks = yes 54 | path = 55 | read list = 56 | read only = ; yes 57 | store dos attributes = yes 58 | valid users = 59 | veto files = 60 | vfs objects = 61 | write list = 62 | 63 | [example] 64 | ; share parameters 65 | comment = read only /tmp access 66 | path = /tmp 67 | -------------------------------------------------------------------------------- /ksmbdpwd.db.5.in: -------------------------------------------------------------------------------- 1 | .TH KSMBDPWD.DB "5" "" "ksmbd-tools @ksmbd_tools_version@" "File Formats and Conventions" 2 | .SH NAME 3 | ksmbdpwd.db \- the user database for ksmbd.mountd 4 | .SH DESCRIPTION 5 | \fBksmbdpwd.db\fR is the user database for \fBksmbd.mountd\fR(8) user mode daemon. 6 | \fBksmbd.adduser\fR(8) may be used for configuring users for \fBksmbdpwd.db\fR. 7 | \fBksmbd.adduser\fR notifies \fBksmbd.mountd\fR of changes, if it had made any, by sending the \fBSIGHUP\fR signal to \fBksmbd.mountd\fR. 8 | \fBksmbd.control \-\-reload\fR can be used for notifying \fBksmbd.mountd\fR of changes when not using \fBksmbd.adduser\fR. 9 | \fBksmbdpwd.db\fR is expected to be at \fB@sysconfdir@/ksmbd/ksmbdpwd.db\fR by default. \" PATH_PWDDB 10 | .SH "FILE FORMAT" 11 | \fBksmbdpwd.db\fR consists of users separated by newlines. 12 | Each user consists of a name and a password, in that order, separated by a colon (\fB:\fR). 13 | The name must be UTF-8 and [1, 48) bytes. \" KSMBD_REQ_MAX_ACCOUNT_NAME_SZ 14 | The password is created from the user-input UTF-8 password, [0, 129) bytes, by converting it to UTF-16LE, then MD4-hashing it, and finally Base64-encoding and padding it. \" MAX_NT_PWD_LEN 15 | .SH COPYRIGHT 16 | Copyright \(co 2015-2022 ksmbd-tools contributors. 17 | License GPLv2: GNU GPL version 2 . 18 | .br 19 | This is free software: you are free to change and redistribute it. 20 | There is NO WARRANTY, to the extent permitted by law. 21 | .SH "REPORTING BUGS" 22 | For bug reports, use the issue tracker at https://github.com/cifsd-team/ksmbd-tools/issues. 23 | .SH "SEE ALSO" 24 | .TP 25 | \fBUtilities\fR 26 | \fBksmbd.adduser\fR(8), 27 | \fBksmbd.mountd\fR(8) 28 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: jammy 2 | 3 | language: c 4 | 5 | notifications: 6 | - email: true 7 | 8 | before_install: 9 | - sudo apt-get install libnl-3-dev libnl-genl-3-dev krb5-multidev heimdal-multidev ninja-build 10 | - gcc --version 11 | - g++ --version 12 | - pip3 install --user meson 13 | - PATH=$HOME/.local/bin:$PATH 14 | 15 | jobs: 16 | include: 17 | - 18 | before_script: 19 | - ./autogen.sh 20 | - ./configure 21 | name: "autotools build without krb5" 22 | script: 23 | - make DISTCHECK_CONFIGURE_FLAGS=--enable-krb5=no distcheck 24 | - 25 | before_script: 26 | - ./autogen.sh 27 | - ./configure 28 | name: "autotools build with mit krb5" 29 | script: 30 | - make DISTCHECK_CONFIGURE_FLAGS="LIBKRB5_CFLAGS='$(krb5-config.mit --cflags)' LIBKRB5_LIBS='$(krb5-config.mit --libs)' --enable-krb5" distcheck 31 | - 32 | before_script: 33 | - ./autogen.sh 34 | - ./configure 35 | name: "autotools build with heimdal krb5" 36 | script: 37 | - make DISTCHECK_CONFIGURE_FLAGS="LIBKRB5_CFLAGS='$(krb5-config.heimdal --cflags)' LIBKRB5_LIBS='$(krb5-config.heimdal --libs) -lasn1' --enable-krb5" distcheck 38 | - 39 | before_script: 40 | - mkdir build 41 | - cd build 42 | name: "meson build without krb5" 43 | script: 44 | - meson -Dkrb5=disabled .. 45 | - meson dist 46 | - 47 | before_script: 48 | - mkdir build 49 | - cd build 50 | name: "meson build with mit krb5" 51 | script: 52 | - meson -Dkrb5=enabled .. 53 | - meson dist 54 | - 55 | before_script: 56 | - mkdir build 57 | - cd build 58 | name: "meson build with heimdal krb5" 59 | script: 60 | - meson -Dkrb5=enabled -Dkrb5_name=heimdal-krb5 .. 61 | - meson dist 62 | -------------------------------------------------------------------------------- /include/config_parser.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /* 3 | * Copyright (C) 2018 Samsung Electronics Co., Ltd. 4 | * 5 | * linux-cifsd-devel@lists.sourceforge.net 6 | */ 7 | 8 | #ifndef __KSMBD_CONFIG_H__ 9 | #define __KSMBD_CONFIG_H__ 10 | 11 | #include 12 | 13 | struct smbconf_group { 14 | char *name; 15 | GHashTable *kv; 16 | }; 17 | 18 | struct smbconf_parser { 19 | GHashTable *groups; 20 | struct smbconf_group *current, *global, *ipc; 21 | }; 22 | 23 | extern struct smbconf_parser parser; 24 | 25 | static inline int cp_printable(unsigned char *p) 26 | { 27 | /* eighth bit is ok due to utf-8 mb */ 28 | return (*p >= 0x20 && *p != 0x7F) || *p == '\t'; 29 | } 30 | 31 | static inline int cp_smbconf_eol(char *p) 32 | { 33 | return *p == 0x00 || *p == ';' || *p == '#'; 34 | } 35 | 36 | static inline int cp_pwddb_eol(char *p) 37 | { 38 | return *p == 0x00; 39 | } 40 | 41 | void cp_parse_external_smbconf_group(char *name, char **options); 42 | void cp_smbconf_parser_init(void); 43 | void cp_smbconf_parser_destroy(void); 44 | 45 | int cp_parse_smbconf(char *smbconf); 46 | int cp_parse_pwddb(char *pwddb); 47 | int cp_parse_subauth(void); 48 | int cp_parse_lock(void); 49 | 50 | unsigned long long cp_memparse(char *v); 51 | char *cp_ltrim(const char *v); 52 | char *cp_rtrim(const char *v, const char *p); 53 | int cp_key_cmp(const char *lk, const char *rk); 54 | char *cp_get_group_kv_string(char *v); 55 | int cp_get_group_kv_bool(char *v); 56 | unsigned long cp_get_group_kv_long_base(char *v, int base); 57 | unsigned long cp_get_group_kv_long(char *v); 58 | int cp_get_group_kv_config_opt(char *v); 59 | char **cp_get_group_kv_list(char *v); 60 | void cp_group_kv_list_free(char **list); 61 | int cp_group_kv_steal(GHashTable *kv, const char *lookup, char **k, char **v); 62 | 63 | #endif /* __KSMBD_CONFIG_H__ */ 64 | -------------------------------------------------------------------------------- /include/management/user.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /* 3 | * Copyright (C) 2018 Samsung Electronics Co., Ltd. 4 | * 5 | * linux-cifsd-devel@lists.sourceforge.net 6 | */ 7 | 8 | #ifndef __MANAGEMENT_USER_H__ 9 | #define __MANAGEMENT_USER_H__ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | struct ksmbd_user { 16 | char *name; 17 | char *pass_b64; 18 | 19 | char *pass; 20 | int pass_sz; 21 | 22 | uid_t uid; 23 | gid_t gid; 24 | 25 | int ref_count; 26 | int flags; 27 | int state; 28 | GRWLock update_lock; 29 | unsigned int failed_login_count; 30 | int ngroups; 31 | gid_t *sgid; 32 | }; 33 | 34 | static inline void set_user_flag(struct ksmbd_user *user, int bit) 35 | { 36 | user->flags |= bit; 37 | } 38 | 39 | static inline int test_user_flag(struct ksmbd_user *user, int bit) 40 | { 41 | return user->flags & bit; 42 | } 43 | 44 | int usm_remove_user(struct ksmbd_user *user); 45 | struct ksmbd_user *get_ksmbd_user(struct ksmbd_user *user); 46 | void put_ksmbd_user(struct ksmbd_user *user); 47 | 48 | struct ksmbd_user *usm_lookup_user(char *name); 49 | 50 | void usm_update_user_password(struct ksmbd_user *user, char *pass); 51 | 52 | int usm_user_name(char *name, char *p); 53 | int usm_add_new_user(char *name, char *pwd); 54 | int usm_add_guest_account(char *name); 55 | 56 | void usm_remove_all_users(void); 57 | 58 | void usm_destroy(void); 59 | void usm_init(void); 60 | 61 | typedef void (*user_cb)(struct ksmbd_user *user, void *data); 62 | void usm_iter_users(user_cb cb, void *data); 63 | 64 | struct ksmbd_login_request; 65 | struct ksmbd_login_response; 66 | struct ksmbd_login_response_ext; 67 | struct ksmbd_logout_request; 68 | 69 | int usm_handle_login_request(struct ksmbd_login_request *req, 70 | struct ksmbd_login_response *resp); 71 | int usm_handle_logout_request(struct ksmbd_logout_request *req); 72 | int usm_handle_login_request_ext(struct ksmbd_login_request *req, 73 | struct ksmbd_login_response_ext *resp); 74 | 75 | #endif /* __MANAGEMENT_USER_H__ */ 76 | -------------------------------------------------------------------------------- /control/ksmbd.control.8.in: -------------------------------------------------------------------------------- 1 | .TH KSMBD.CONTROL "8" "" "ksmbd-tools @ksmbd_tools_version@" "System Administration" 2 | .SH NAME 3 | ksmbd.control \- control ksmbd.mountd and ksmbd daemons 4 | .SH SYNOPSIS 5 | .B ksmbd.control 6 | [\-v] \-s 7 | .br 8 | .B ksmbd.control 9 | [\-v] \-r 10 | .br 11 | .B ksmbd.control 12 | [\-v] \-l 13 | .br 14 | .B ksmbd.control 15 | [\-v] \-d \fI\,COMPONENT\/\fR 16 | .br 17 | .B ksmbd.control 18 | [\-v] \-c 19 | .SH DESCRIPTION 20 | \fBksmbd.control\fR controls \fBksmbd.mountd\fR(8) user mode and \fBksmbd\fR kernel mode daemons. 21 | .SH OPTIONS 22 | .TP 23 | \fB\-s\fR, \fB\-\-shutdown\fR 24 | Shutdown both \fBksmbd.mountd\fR and \fBksmbd\fR and exit. 25 | .TP 26 | \fB\-r\fR, \fB\-\-reload\fR 27 | Notify \fBksmbd.mountd\fR of changes and exit. 28 | .TP 29 | \fB\-l\fR, \fB\-\-list\fR 30 | List \fBksmbd.mountd\fR shares and exit. 31 | .TP 32 | \fB\-d\fR, \fB\-\-debug\fR=\fI\,COMPONENT\/\fR 33 | Toggle \fBksmbd\fR debug printing for \fI\,COMPONENT\/\fR and exit. 34 | \fI\,COMPONENT\/\fR is \fBall\fR, \fBsmb\fR, \fBauth\fR, \fBvfs\fR, \fBoplock\fR, \fBipc\fR, \fBconn\fR, or \fBrdma\fR. 35 | Enabled ones are output enclosed in brackets (\fB[]\fR). 36 | .TP 37 | \fB\-c\fR, \fB\-\-ksmbd-version\fR 38 | Output \fBksmbd\fR version information and exit. 39 | .TP 40 | \fB\-v\fR, \fB\-\-verbose\fR 41 | Be verbose. 42 | .TP 43 | \fB\-V\fR, \fB\-\-version\fR 44 | Output version information and exit. 45 | .TP 46 | \fB\-h\fR, \fB\-\-help\fR 47 | Display this help and exit. 48 | .SH "EXIT STATUS" 49 | The exit status is 0 on success and 1 on failure. 50 | .SH COPYRIGHT 51 | Copyright \(co 2015-2022 ksmbd-tools contributors. 52 | License GPLv2: GNU GPL version 2 . 53 | .br 54 | This is free software: you are free to change and redistribute it. 55 | There is NO WARRANTY, to the extent permitted by law. 56 | .SH "REPORTING BUGS" 57 | For bug reports, use the issue tracker at https://github.com/cifsd-team/ksmbd-tools/issues. 58 | .SH "SEE ALSO" 59 | .TP 60 | \fBUtilities\fR 61 | \fBksmbd.addshare\fR(8), 62 | \fBksmbd.adduser\fR(8), 63 | \fBksmbd.mountd\fR(8) 64 | -------------------------------------------------------------------------------- /ksmbd-tools.spec: -------------------------------------------------------------------------------- 1 | # 2 | # spec file for package ksmbd-tools 3 | # 4 | # Copyright (c) 2021 SUSE LLC 5 | # 6 | # All modifications and additions to the file contributed by third parties 7 | # remain the property of their copyright owners, unless otherwise agreed 8 | # upon. The license for this file, and modifications and additions to the 9 | # file, is the same license as for the pristine package itself (unless the 10 | # license for the pristine package is not an Open Source License, in which 11 | # case the license is the MIT License). An "Open Source License" is a 12 | # license that conforms to the Open Source Definition (Version 1.9) 13 | # published by the Open Source Initiative. 14 | # 15 | # Please submit bugfixes or comments via https://bugs.opensuse.org/ 16 | # 17 | 18 | Name: ksmbd-tools 19 | Version: master 20 | Release: 0 21 | Summary: ksmbd kernel server userspace utilities 22 | License: GPL-2.0-or-later 23 | Group: System/Filesystems 24 | Url: https://github.com/cifsd-team/ksmbd-tools 25 | Source: %{url}/archive/%{version}/%{name}-%{version}.tar.gz 26 | 27 | BuildRequires: glib2-devel 28 | BuildRequires: libnl3-devel 29 | BuildRequires: autoconf 30 | BuildRequires: automake 31 | BuildRequires: libtool 32 | BuildRequires: systemd-rpm-macros 33 | 34 | Requires(pre): kernel-default >= 5.15 35 | Requires(pre): systemd >= 245 36 | 37 | %description 38 | Collection of userspace utilities for the ksmbd kernel server. 39 | 40 | %prep 41 | %setup -q 42 | 43 | %build 44 | ./autogen.sh 45 | %configure --with-systemdsystemunitdir=%{_unitdir} 46 | make %{?_smp_mflags} 47 | 48 | %install 49 | %make_install 50 | 51 | %files 52 | %{_sbindir}/ksmbd.addshare 53 | %{_sbindir}/ksmbd.adduser 54 | %{_sbindir}/ksmbd.control 55 | %{_sbindir}/ksmbd.mountd 56 | %{_libexecdir}/ksmbd.tools 57 | %{_mandir}/man8/ksmbd.addshare.8* 58 | %{_mandir}/man8/ksmbd.adduser.8* 59 | %{_mandir}/man8/ksmbd.control.8* 60 | %{_mandir}/man8/ksmbd.mountd.8* 61 | %{_mandir}/man5/ksmbd.conf.5* 62 | %{_mandir}/man5/ksmbdpwd.db.5* 63 | %{_sysconfdir}/ksmbd/ksmbd.conf.example 64 | %{_unitdir}/ksmbd.service 65 | 66 | %changelog 67 | -------------------------------------------------------------------------------- /.github/workflows/c-cpp.yml: -------------------------------------------------------------------------------- 1 | name: ksmbd-tools CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - next 8 | pull_request: 9 | branches: 10 | - master 11 | - next 12 | 13 | jobs: 14 | build: 15 | 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - uses: actions/checkout@v4 20 | - name: Prerequisite for build test 21 | run: | 22 | sudo apt-get install libnl-3-dev libnl-genl-3-dev krb5-multidev heimdal-multidev ninja-build libglib2.0-dev 23 | gcc --version 24 | g++ --version 25 | pip3 install --user meson 26 | PATH=$HOME/.local/bin:$PATH 27 | ./autogen.sh 28 | - name: autotools build without krb5 29 | run: | 30 | mkdir autotools-no-krb5-build 31 | cd autotools-no-krb5-build 32 | ../configure 33 | make DISTCHECK_CONFIGURE_FLAGS=--enable-krb5=no distcheck 34 | - name: autotools build with mit krb5 35 | run: | 36 | mkdir autotools-mit-krb5-build 37 | cd autotools-mit-krb5-build 38 | ../configure 39 | make DISTCHECK_CONFIGURE_FLAGS="LIBKRB5_CFLAGS='$(krb5-config.mit --cflags)' LIBKRB5_LIBS='$(krb5-config.mit --libs)' --enable-krb5" distcheck 40 | - name: autotools build with heimdal krb5 41 | run: | 42 | mkdir autotools-heimdal-krb5-build 43 | cd autotools-heimdal-krb5-build 44 | ../configure 45 | make DISTCHECK_CONFIGURE_FLAGS="LIBKRB5_CFLAGS='$(krb5-config.heimdal --cflags)' LIBKRB5_LIBS='$(krb5-config.heimdal --libs) -lasn1' --enable-krb5" distcheck 46 | - name: meson build without krb5 47 | run: | 48 | mkdir meson-no-krb5-build 49 | cd meson-no-krb5-build 50 | meson -Dkrb5=disabled .. 51 | meson dist 52 | - name: meson build with mit krb5 53 | run: | 54 | mkdir meson-mit-krb5-build 55 | cd meson-mit-krb5-build 56 | meson -Dkrb5=enabled -Dkrb5_name=mit-krb5 .. 57 | meson dist 58 | - name: meson build with heimdal krb5 59 | run: | 60 | mkdir meson-heimdal-krb5-build 61 | cd meson-heimdal-krb5-build 62 | meson -Dkrb5=enabled -Dkrb5_name=heimdal-krb5 .. 63 | meson dist 64 | -------------------------------------------------------------------------------- /mountd/ksmbd.mountd.8.in: -------------------------------------------------------------------------------- 1 | .TH KSMBD.MOUNTD "8" "" "ksmbd-tools @ksmbd_tools_version@" "System Administration" 2 | .SH NAME 3 | ksmbd.mountd \- start ksmbd.mountd and ksmbd daemons 4 | .SH SYNOPSIS 5 | .B ksmbd.mountd 6 | [\-v] [\-p \fI\,PORT\/\fR] [\-n[\fI\,WAY\/\fR]] [\-C \fI\,CONF\/\fR] [\-P \fI\,PWDDB\/\fR] 7 | .SH DESCRIPTION 8 | \fBksmbd.mountd\fR starts \fBksmbd.mountd\fR user mode and \fBksmbd\fR kernel mode daemons. 9 | \fBksmbd.mountd\fR has to parse \fBksmbd.conf\fR(5) configuration file in order to start. 10 | \fBksmbd.mountd\fR can parse \fBksmbdpwd.db\fR(5) user database so as to support non-guest sessions. 11 | .SH OPTIONS 12 | .TP 13 | \fB\-p\fR, \fB\-\-port\fR=\fI\,PORT\/\fR 14 | Bind to \fI\,PORT\/\fR instead of TCP port \fB445\fR. 15 | .TP 16 | \fB\-n\fR, \fB\-\-nodetach\fR[=\fI\,WAY\/\fR] 17 | Do not detach process from foreground. 18 | If \fI\,WAY\/\fR is \fB1\fR, become process group leader (default). 19 | If \fI\,WAY\/\fR is \fB0\fR, detach. 20 | .TP 21 | \fB\-C\fR, \fB\-\-config\fR=\fI\,CONF\/\fR 22 | Use \fI\,CONF\/\fR as configuration file instead of \fB@sysconfdir@/ksmbd/ksmbd.conf\fR. \" PATH_SMBCONF 23 | .TP 24 | \fB\-P\fR, \fB\-\-pwddb\fR=\fI\,PWDDB\/\fR 25 | Use \fI\,PWDDB\/\fR as user database instead of \fB@sysconfdir@/ksmbd/ksmbdpwd.db\fR. \" PATH_PWDDB 26 | .TP 27 | \fB\-v\fR, \fB\-\-verbose\fR 28 | Be verbose. 29 | .TP 30 | \fB\-V\fR, \fB\-\-version\fR 31 | Output version information and exit. 32 | .TP 33 | \fB\-h\fR, \fB\-\-help\fR 34 | Display this help and exit. 35 | .SH "EXIT STATUS" 36 | The exit status is 0 on success and 1 on failure. 37 | When detaching process from foreground, exit status is 0 if daemonization succeeded. 38 | .SH SIGNALS 39 | \fBksmbd.mountd\fR can be notified of changes to \fBksmbd.conf\fR or \fBksmbdpwd.db\fR by sending it the \fBSIGHUP\fR signal. 40 | The manager process of \fBksmbd.mountd\fR has its PID stored in \fB@runstatedir@/ksmbd.lock\fR. \" PATH_LOCK 41 | .SH COPYRIGHT 42 | Copyright \(co 2015-2022 ksmbd-tools contributors. 43 | License GPLv2: GNU GPL version 2 . 44 | .br 45 | This is free software: you are free to change and redistribute it. 46 | There is NO WARRANTY, to the extent permitted by law. 47 | .SH "REPORTING BUGS" 48 | For bug reports, use the issue tracker at https://github.com/cifsd-team/ksmbd-tools/issues. 49 | .SH "SEE ALSO" 50 | .TP 51 | \fBConfiguration File\fR 52 | \fBksmbd.conf\fR(5) 53 | .TP 54 | \fBUser Database\fR 55 | \fBksmbdpwd.db\fR(5) 56 | .TP 57 | \fBUtilities\fR 58 | \fBksmbd.addshare\fR(8), 59 | \fBksmbd.adduser\fR(8), 60 | \fBksmbd.control\fR(8) 61 | -------------------------------------------------------------------------------- /include/smbacl.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ 2 | /* 3 | * Copyright (c) International Business Machines Corp., 2007 4 | * Author(s): Steve French (sfrench@us.ibm.com) 5 | * Copyright (C) 2020 Samsung Electronics Co., Ltd. 6 | * Author(s): Namjae Jeon (linkinjeon@kernel.org) 7 | */ 8 | 9 | #ifndef __KSMBD_SMBACL_H__ 10 | #define __KSMBD_SMBACL_H__ 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #define NUM_AUTHS (6) /* number of authority fields */ 17 | #define SID_MAX_SUB_AUTHORITIES (15) /* max number of sub authority fields */ 18 | 19 | #define ACCESS_ALLOWED 0 20 | #define ACCESS_DENIED 1 21 | 22 | /* Control flags for Security Descriptor */ 23 | #define OWNER_DEFAULTED 0x0001 24 | #define GROUP_DEFAULTED 0x0002 25 | #define DACL_PRESENT 0x0004 26 | #define DACL_DEFAULTED 0x0008 27 | #define SACL_PRESENT 0x0010 28 | #define SACL_DEFAULTED 0x0020 29 | #define DACL_TRUSTED 0x0040 30 | #define SERVER_SECURITY 0x0080 31 | #define DACL_AUTO_INHERIT_REQ 0x0100 32 | #define SACL_AUTO_INHERIT_REQ 0x0200 33 | #define DACL_AUTO_INHERITED 0x0400 34 | #define SACL_AUTO_INHERITED 0x0800 35 | #define DACL_PROTECTED 0x1000 36 | #define SACL_PROTECTED 0x2000 37 | #define RM_CONTROL_VALID 0x4000 38 | #define SELF_RELATIVE 0x8000 39 | 40 | #define SID_TYPE_USER 1 41 | #define SID_TYPE_GROUP 2 42 | #define SID_TYPE_UNKNOWN 8 43 | 44 | struct smb_ntsd { 45 | __u16 revision; /* revision level */ 46 | __u16 type; 47 | __u32 osidoffset; 48 | __u32 gsidoffset; 49 | __u32 sacloffset; 50 | __u32 dacloffset; 51 | }; 52 | 53 | struct smb_sid { 54 | __u8 revision; /* revision level */ 55 | __u8 num_subauth; 56 | __u8 authority[NUM_AUTHS]; 57 | __u32 sub_auth[SID_MAX_SUB_AUTHORITIES]; /* sub_auth[num_subauth] */ 58 | }; 59 | 60 | struct smb_acl { 61 | __u16 revision; /* revision level */ 62 | __u16 size; 63 | __u32 num_aces; 64 | }; 65 | 66 | struct smb_ace { 67 | __u8 type; 68 | __u8 flags; 69 | __u16 size; 70 | __u32 access_req; 71 | struct smb_sid sid; /* ie UUID of user or group who gets these perms */ 72 | }; 73 | 74 | void smb_init_domain_sid(struct smb_sid *sid); 75 | int smb_read_sid(struct ksmbd_dcerpc *dce, struct smb_sid *sid); 76 | int smb_write_sid(struct ksmbd_dcerpc *dce, const struct smb_sid *src); 77 | void smb_copy_sid(struct smb_sid *dst, const struct smb_sid *src); 78 | int smb_compare_sids(const struct smb_sid *ctsid, const struct smb_sid *cwsid); 79 | int build_sec_desc(struct ksmbd_dcerpc *dce, __u32 *secdesclen, int rid); 80 | int set_domain_name(struct smb_sid *sid, char *domain, size_t domain_len, int *type); 81 | #endif /* __KSMBD_SMBACL_H__ */ 82 | -------------------------------------------------------------------------------- /adduser/ksmbd.adduser.8.in: -------------------------------------------------------------------------------- 1 | .TH KSMBD.ADDUSER "8" "" "ksmbd-tools @ksmbd_tools_version@" "System Administration" 2 | .SH NAME 3 | ksmbd.adduser \- configure users for ksmbdpwd.db of ksmbd.mountd 4 | .SH SYNOPSIS 5 | .B ksmbd.adduser 6 | [\-v] [\-P \fI\,PWDDB\/\fR] [\-C \fI\,CONF\/\fR] [\-a | \-u | \-d] [\-p \fI\,PWD\/\fR] \fI\,USER\/\fR 7 | .SH DESCRIPTION 8 | \fBksmbd.adduser\fR configures users for \fBksmbdpwd.db\fR(5) user database of \fBksmbd.mountd\fR(8) user mode daemon. 9 | \fBksmbd.adduser\fR can parse \fBksmbd.conf\fR(5) configuration file so as to guard against deletion of users that are depended on. 10 | \fBksmbd.adduser\fR notifies \fBksmbd.mountd\fR of changes if it had made any. 11 | .SH OPTIONS 12 | .PP 13 | If neither \fB\-a\fR, \fB\-u\fR, nor \fB\-d\fR is given, either add or update \fI\,USER\/\fR. 14 | \fI\,USER\/\fR must be UTF-8 and [1, 48) bytes. \" KSMBD_REQ_MAX_ACCOUNT_NAME_SZ 15 | \fI\,USER\/\fR cannot contain colon (\fB:\fR). 16 | .TP 17 | \fB\-a\fR, \fB\-\-add\/\fR 18 | Add \fI\,USER\/\fR to user database. 19 | .TP 20 | \fB\-u\fR, \fB\-\-update\/\fR 21 | Update \fI\,USER\/\fR in user database. 22 | .TP 23 | \fB\-d\fR, \fB\-\-delete\/\fR 24 | Delete \fI\,USER\/\fR from user database. 25 | .TP 26 | \fB\-p\fR, \fB\-\-password\fR=\fI\,PWD\/\fR 27 | Use \fI\,PWD\/\fR as user password instead of prompting. 28 | \fI\,PWD\/\fR must be UTF-8 and [0, 129) bytes. \" MAX_NT_PWD_LEN 29 | .TP 30 | \fB\-P\fR, \fB\-\-pwddb\fR=\fI\,PWDDB\/\fR 31 | Use \fI\,PWDDB\/\fR as user database instead of \fB@sysconfdir@/ksmbd/ksmbdpwd.db\fR. \" PATH_PWDDB 32 | .TP 33 | \fB\-C\fR, \fB\-\-config\fR=\fI\,CONF\/\fR 34 | Use \fI\,CONF\/\fR as configuration file instead of \fB@sysconfdir@/ksmbd/ksmbd.conf\fR. \" PATH_SMBCONF 35 | .TP 36 | \fB\-v\fR, \fB\-\-verbose\fR 37 | Be verbose. 38 | .TP 39 | \fB\-V\fR, \fB\-\-version\fR 40 | Output version information and exit. 41 | .TP 42 | \fB\-h\fR, \fB\-\-help\fR 43 | Display this help and exit. 44 | .SH "EXIT STATUS" 45 | The exit status is 0 on success and 1 on failure. 46 | Failure to notify \fBksmbd.mountd\fR of changes has no effect on exit status. 47 | .SH COPYRIGHT 48 | Copyright \(co 2015-2022 ksmbd-tools contributors. 49 | License GPLv2: GNU GPL version 2 . 50 | .br 51 | This is free software: you are free to change and redistribute it. 52 | There is NO WARRANTY, to the extent permitted by law. 53 | .SH "REPORTING BUGS" 54 | For bug reports, use the issue tracker at https://github.com/cifsd-team/ksmbd-tools/issues. 55 | .SH "SEE ALSO" 56 | .TP 57 | \fBUser Database\fR 58 | \fBksmbdpwd.db\fR(5) 59 | .TP 60 | \fBConfiguration File\fR 61 | \fBksmbd.conf\fR(5) 62 | .TP 63 | \fBUtilities\fR 64 | \fBksmbd.addshare\fR(8), 65 | \fBksmbd.control\fR(8), 66 | \fBksmbd.mountd\fR(8) 67 | -------------------------------------------------------------------------------- /addshare/ksmbd.addshare.8.in: -------------------------------------------------------------------------------- 1 | .TH KSMBD.ADDSHARE "8" "" "ksmbd-tools @ksmbd_tools_version@" "System Administration" 2 | .SH NAME 3 | ksmbd.addshare \- configure shares for ksmbd.conf of ksmbd.mountd 4 | .SH SYNOPSIS 5 | .B ksmbd.addshare 6 | [\-v] [\-C \fI\,CONF\/\fR] [\-P \fI\,PWDDB\/\fR] [\-a | \-u | \-d] [\-o \fI\,OPT\/\fR]... \fI\,SHARE\/\fR 7 | .SH DESCRIPTION 8 | \fBksmbd.addshare\fR configures shares for \fBksmbd.conf\fR(5) configuration file of \fBksmbd.mountd\fR(8) user mode daemon. 9 | \fBksmbd.addshare\fR modifies \fBksmbd.conf\fR such that its existing formatting is not retained. 10 | \fBksmbd.addshare\fR can parse \fBksmbdpwd.db\fR(5) user database so as to provide completions when prompting. 11 | \fBksmbd.addshare\fR notifies \fBksmbd.mountd\fR of changes if it had made any. 12 | \fBksmbd.addshare\fR will only make changes that do not require restarting \fBksmbd.mountd\fR and \fBksmbd\fR to take effect. 13 | .SH OPTIONS 14 | .PP 15 | If neither \fB\-a\fR, \fB\-u\fR, nor \fB\-d\fR is given, either add or update \fI\,SHARE\/\fR. 16 | \fI\,SHARE\/\fR must be UTF-8 and [1, 64) bytes. \" KSMBD_REQ_MAX_SHARE_NAME 17 | \fI\,SHARE\/\fR is case-insensitive. 18 | .TP 19 | \fB\-a\fR, \fB\-\-add\/\fR 20 | Add \fI\,SHARE\/\fR to configuration file. 21 | .TP 22 | \fB\-u\fR, \fB\-\-update\/\fR 23 | Update \fI\,SHARE\/\fR in configuration file. 24 | .TP 25 | \fB\-d\fR, \fB\-\-delete\/\fR 26 | Delete \fI\,SHARE\/\fR from configuration file. 27 | .TP 28 | \fB\-o\fR, \fB\-\-option\fR=\fI\,OPT\/\fR 29 | Use \fI\,OPT\/\fR as share parameter instead of prompting. 30 | This option can be given multiple times. 31 | .TP 32 | \fB\-C\fR, \fB\-\-config\fR=\fI\,CONF\/\fR 33 | Use \fI\,CONF\/\fR as configuration file instead of \fB@sysconfdir@/ksmbd/ksmbd.conf\fR. \" PATH_SMBCONF 34 | .TP 35 | \fB\-P\fR, \fB\-\-pwddb\fR=\fI\,PWDDB\/\fR 36 | Use \fI\,PWDDB\/\fR as user database instead of \fB@sysconfdir@/ksmbd/ksmbdpwd.db\fR. \" PATH_PWDDB 37 | .TP 38 | \fB\-v\fR, \fB\-\-verbose\fR 39 | Be verbose. 40 | .TP 41 | \fB\-V\fR, \fB\-\-version\fR 42 | Output version information and exit. 43 | .TP 44 | \fB\-h\fR, \fB\-\-help\fR 45 | Display this help and exit. 46 | .SH "EXIT STATUS" 47 | The exit status is 0 on success and 1 on failure. 48 | Failure to notify \fBksmbd.mountd\fR of changes has no effect on exit status. 49 | .SH COPYRIGHT 50 | Copyright \(co 2015-2022 ksmbd-tools contributors. 51 | License GPLv2: GNU GPL version 2 . 52 | .br 53 | This is free software: you are free to change and redistribute it. 54 | There is NO WARRANTY, to the extent permitted by law. 55 | .SH "REPORTING BUGS" 56 | For bug reports, use the issue tracker at https://github.com/cifsd-team/ksmbd-tools/issues. 57 | .SH "SEE ALSO" 58 | .TP 59 | \fBConfiguration File\fR 60 | \fBksmbd.conf\fR(5) 61 | .TP 62 | \fBUser Database\fR 63 | \fBksmbdpwd.db\fR(5) 64 | .TP 65 | \fBUtilities\fR 66 | \fBksmbd.adduser\fR(8), 67 | \fBksmbd.control\fR(8), 68 | \fBksmbd.mountd\fR(8) 69 | -------------------------------------------------------------------------------- /include/asn1.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | 3 | #ifndef ASN1_DECODER_H_ 4 | #define ASN1_DECODER_H_ 5 | 6 | /* Class */ 7 | #define ASN1_UNI 0 /* Universal */ 8 | #define ASN1_APL 1 /* Application */ 9 | #define ASN1_CTX 2 /* Context */ 10 | #define ASN1_PRV 3 /* Private */ 11 | 12 | /* Tag */ 13 | #define ASN1_EOC 0 /* End Of Contents or N/A */ 14 | #define ASN1_BOL 1 /* Boolean */ 15 | #define ASN1_INT 2 /* Integer */ 16 | #define ASN1_BTS 3 /* Bit String */ 17 | #define ASN1_OTS 4 /* Octet String */ 18 | #define ASN1_NUL 5 /* Null */ 19 | #define ASN1_OJI 6 /* Object Identifier */ 20 | #define ASN1_OJD 7 /* Object Description */ 21 | #define ASN1_EXT 8 /* External */ 22 | #define ASN1_ENUM 10 /* Enumerated */ 23 | #define ASN1_SEQ 16 /* Sequence */ 24 | #define ASN1_SET 17 /* Set */ 25 | #define ASN1_NUMSTR 18 /* Numerical String */ 26 | #define ASN1_PRNSTR 19 /* Printable String */ 27 | #define ASN1_TEXSTR 20 /* Teletext String */ 28 | #define ASN1_VIDSTR 21 /* Video String */ 29 | #define ASN1_IA5STR 22 /* IA5 String */ 30 | #define ASN1_UNITIM 23 /* Universal Time */ 31 | #define ASN1_GENTIM 24 /* General Time */ 32 | #define ASN1_GRASTR 25 /* Graphical String */ 33 | #define ASN1_VISSTR 26 /* Visible String */ 34 | #define ASN1_GENSTR 27 /* General String */ 35 | 36 | /* Primitive / Constructed methods*/ 37 | #define ASN1_PRI 0 /* Primitive */ 38 | #define ASN1_CON 1 /* Constructed */ 39 | 40 | /* 41 | * Error codes. 42 | */ 43 | #define ASN1_ERR_NOERROR 0 44 | #define ASN1_ERR_DEC_EMPTY 2 45 | #define ASN1_ERR_DEC_EOC_MISMATCH 3 46 | #define ASN1_ERR_DEC_LENGTH_MISMATCH 4 47 | #define ASN1_ERR_DEC_BADVALUE 5 48 | 49 | #define SPNEGO_OID_LEN 7 50 | #define NTLMSSP_OID_LEN 10 51 | #define KRB5_OID_LEN 7 52 | #define KRB5U2U_OID_LEN 8 53 | #define MSKRB5_OID_LEN 7 54 | static unsigned long SPNEGO_OID[7] = { 1, 3, 6, 1, 5, 5, 2 }; 55 | static unsigned long NTLMSSP_OID[10] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 }; 56 | static unsigned long KRB5_OID[7] = { 1, 2, 840, 113554, 1, 2, 2 }; 57 | static unsigned long KRB5U2U_OID[8] = { 1, 2, 840, 113554, 1, 2, 2, 3 }; 58 | static unsigned long MSKRB5_OID[7] = { 1, 2, 840, 48018, 1, 2, 2 }; 59 | 60 | /* 61 | * ASN.1 context. 62 | */ 63 | struct asn1_ctx { 64 | int error; /* Error condition */ 65 | unsigned char *pointer; /* Octet just to be decoded */ 66 | unsigned char *begin; /* First octet */ 67 | unsigned char *end; /* Octet after last octet */ 68 | }; 69 | 70 | /* 71 | * Octet string (not null terminated) 72 | */ 73 | struct asn1_octstr { 74 | unsigned char *data; 75 | unsigned int len; 76 | }; 77 | 78 | void asn1_open(struct asn1_ctx *ctx, unsigned char *buf, unsigned int len); 79 | unsigned char asn1_header_decode(struct asn1_ctx *ctx, unsigned char **eoc, 80 | unsigned int *cls, unsigned int *con, unsigned int *tag); 81 | unsigned char asn1_octets_decode(struct asn1_ctx *ctx, unsigned char *eoc, 82 | unsigned char **octets, unsigned int *len); 83 | unsigned char asn1_read(struct asn1_ctx *ctx, 84 | unsigned char **buf, unsigned int len); 85 | int asn1_oid_decode(struct asn1_ctx *ctx, unsigned char *eoc, 86 | unsigned long **oid, unsigned int *len); 87 | 88 | int asn1_header_len(unsigned int payload_len, int depth); 89 | int asn1_header_encode(unsigned char **buf, 90 | unsigned int cls, unsigned int con, unsigned int tag, 91 | unsigned int *len); 92 | int asn1_oid_encode(const unsigned long *in_oid, int in_len, 93 | unsigned char **out_oid, int *out_len); 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project( 2 | 'ksmbd-tools', 3 | 'c', 4 | version: run_command( 5 | '/bin/sh', 6 | '-c', 7 | ''' 8 | exec awk '/define KSMBD_TOOLS_VERSION / { gsub(/"/,"",$3); printf "%s", $3 }' include/version.h 9 | ''', 10 | check: true, 11 | ).stdout(), 12 | default_options: 'c_std=gnu99', 13 | meson_version: '>= 0.61.5', 14 | ) 15 | 16 | include_dirs = include_directories( 17 | '.', 18 | 'include', 19 | ) 20 | 21 | glib_dep = dependency( 22 | 'glib-2.0', 23 | version: '>= 2.58', 24 | ) 25 | libnl_dep = dependency( 26 | 'libnl-genl-3.0', 27 | version: '>= 3.0', 28 | ) 29 | systemd_dep = dependency( 30 | 'systemd', 31 | required: false, 32 | version: '>= 245', 33 | ) 34 | krb5_dep = dependency( 35 | get_option('krb5_name'), 36 | required: get_option('krb5'), 37 | ) 38 | asn1_lib = [] 39 | 40 | config_h_data = configuration_data() 41 | cc = meson.get_compiler('c') 42 | 43 | pthread_lib = cc.find_library( 44 | 'pthread', 45 | ) 46 | 47 | if krb5_dep.found() 48 | config_h_data.set( 49 | 'CONFIG_KRB5', 50 | krb5_dep.found(), 51 | ) 52 | config_h_data.set( 53 | 'HAVE_KRB5_AUTH_CON_GETRECVSUBKEY', 54 | cc.has_function( 55 | 'krb5_auth_con_getrecvsubkey', 56 | dependencies: krb5_dep, 57 | ), 58 | ) 59 | config_h_data.set( 60 | 'HAVE_KRB5_KEYBLOCK_KEYVALUE', 61 | cc.has_member( 62 | 'krb5_keyblock', 63 | 'keyvalue', 64 | prefix: '#include ', 65 | dependencies: krb5_dep, 66 | ), 67 | ) 68 | config_h_data.set( 69 | 'HAVE_KRB5_AUTHENTICATOR_CLIENT', 70 | cc.has_member( 71 | 'krb5_authenticator', 72 | 'client', 73 | prefix: '#include ', 74 | dependencies: krb5_dep, 75 | ), 76 | ) 77 | config_h_data.set( 78 | 'HAVE_KRB5_AUTH_CON_GETAUTHENTICATOR_DOUBLE_POINTER', 79 | cc.compiles( 80 | ''' 81 | #include 82 | krb5_error_code krb5_auth_con_getauthenticator(krb5_context, krb5_auth_context, krb5_authenticator**); 83 | ''', 84 | dependencies: krb5_dep, 85 | name: 'krb5_auth_con_getauthenticator has krb5_authenticator** parameter', 86 | ), 87 | ) 88 | if not config_h_data.get('HAVE_KRB5_AUTHENTICATOR_CLIENT') 89 | asn1_lib = cc.find_library( 90 | 'asn1', 91 | dirs: krb5_dep.get_variable(pkgconfig: 'libdir'), 92 | ) 93 | endif 94 | endif 95 | 96 | configure_file( 97 | output: 'config.h', 98 | configuration: config_h_data, 99 | ) 100 | 101 | add_project_arguments( 102 | '-DHAVE_CONFIG_H', 103 | language: 'c', 104 | ) 105 | 106 | rundir = get_option('rundir') 107 | if rundir == '' 108 | if false # meson.version().version_compare('>= ') 109 | runstatedir = get_option('prefix') / get_option('runstatedir') 110 | else 111 | runstatedir = get_option('prefix') / get_option('localstatedir') / 'run' 112 | endif 113 | else 114 | runstatedir = rundir 115 | endif 116 | 117 | install_data( 118 | sources: 'ksmbd.conf.example', 119 | install_dir: get_option('sysconfdir') / 'ksmbd', 120 | ) 121 | 122 | systemdsystemunitdir = get_option('systemdsystemunitdir') 123 | if systemdsystemunitdir == '' 124 | systemdsystemunitdir = systemd_dep.get_variable( 125 | pkgconfig: 'systemdsystemunitdir', 126 | default_value: '', 127 | ) 128 | endif 129 | 130 | in_data = configuration_data({ 131 | 'sbindir': get_option('prefix') / get_option('sbindir'), 132 | 'sysconfdir': get_option('prefix') / get_option('sysconfdir'), 133 | 'runstatedir': runstatedir, 134 | 'ksmbd_tools_version': meson.project_version(), 135 | }) 136 | 137 | configure_file( 138 | input: 'ksmbd.conf.5.in', 139 | output: 'ksmbd.conf.5', 140 | install_dir: get_option('mandir') / 'man5', 141 | configuration: in_data, 142 | ) 143 | 144 | configure_file( 145 | input: 'ksmbdpwd.db.5.in', 146 | output: 'ksmbdpwd.db.5', 147 | install_dir: get_option('mandir') / 'man5', 148 | configuration: in_data, 149 | ) 150 | 151 | configure_file( 152 | input: 'ksmbd.service.in', 153 | output: 'ksmbd.service', 154 | install_dir: systemdsystemunitdir, 155 | configuration: in_data, 156 | ) 157 | 158 | subdir('addshare') 159 | subdir('adduser') 160 | subdir('control') 161 | subdir('mountd') 162 | subdir('tools') 163 | -------------------------------------------------------------------------------- /adduser/adduser.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * Copyright (C) 2018 Samsung Electronics Co., Ltd. 4 | * 5 | * linux-cifsd-devel@lists.sourceforge.net 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "config_parser.h" 21 | #include "tools.h" 22 | #include "management/user.h" 23 | #include "management/share.h" 24 | #include "user_admin.h" 25 | #include "linux/ksmbd_server.h" 26 | 27 | static void usage(int status) 28 | { 29 | printf( 30 | "Usage: ksmbd.adduser [-v] [-P PWDDB] [-c CONF] [-a | -u | -d] [-p PWD] USER\n"); 31 | 32 | if (status != EXIT_SUCCESS) 33 | printf("Try `ksmbd.adduser --help' for more information.\n"); 34 | else 35 | printf( 36 | "\n" 37 | "If neither `-a', `-u', nor `-d' is given, either add or update USER.\n" 38 | "USER must be UTF-8 and [1, " STR(KSMBD_REQ_MAX_ACCOUNT_NAME_SZ) ") bytes.\n" 39 | "USER cannot contain colon (`:').\n" 40 | "\n" 41 | " -a, --add add USER to user database\n" 42 | " -u, --update update USER in user database\n" 43 | " -d, --delete delete USER from user database\n" 44 | " -p, --password=PWD use PWD as user password instead of prompting;\n" 45 | " PWD must be UTF-8 and [0, " STR(MAX_NT_PWD_LEN) ") bytes\n" 46 | " -P, --pwddb=PWDDB use PWDDB as user database instead of\n" 47 | " `" PATH_PWDDB "'\n" 48 | " -C, --config=CONF use CONF as configuration file instead of\n" 49 | " `" PATH_SMBCONF "'\n" 50 | " -v, --verbose be verbose\n" 51 | " -V, --version output version information and exit\n" 52 | " -h, --help display this help and exit\n" 53 | "\n" 54 | "See ksmbd.adduser(8) for more details.\n"); 55 | } 56 | 57 | static const struct option opts[] = { 58 | {"add", no_argument, NULL, 'a' }, 59 | {"delete", no_argument, NULL, 'd' }, 60 | {"update", no_argument, NULL, 'u' }, 61 | {"password", required_argument, NULL, 'p' }, 62 | {"pwddb", required_argument, NULL, 'P' }, 63 | {"config", required_argument, NULL, 'C' }, 64 | {"verbose", no_argument, NULL, 'v' }, 65 | {"version", no_argument, NULL, 'V' }, 66 | {"help", no_argument, NULL, 'h' }, 67 | {NULL, 0, NULL, 0 } 68 | }; 69 | 70 | int adduser_main(int argc, char **argv) 71 | { 72 | int ret = -EINVAL; 73 | g_autofree char *pwddb = NULL, *name = NULL, *password = NULL; 74 | g_autofree char *smbconf = NULL; 75 | command_fn *command = NULL; 76 | int c; 77 | 78 | while ((c = getopt_long(argc, argv, "audp:P:C:vVh", opts, NULL)) != EOF) 79 | switch (c) { 80 | case 'a': 81 | command = command_add_user; 82 | break; 83 | case 'u': 84 | command = command_update_user; 85 | break; 86 | case 'd': 87 | command = command_delete_user; 88 | break; 89 | case 'p': 90 | g_free(password); 91 | password = g_strdup(optarg); 92 | break; 93 | case 'P': 94 | g_free(pwddb); 95 | pwddb = g_strdup(optarg); 96 | break; 97 | case 'C': 98 | g_free(smbconf); 99 | smbconf = g_strdup(optarg); 100 | break; 101 | case 'v': 102 | set_log_level(PR_DEBUG); 103 | break; 104 | case 'V': 105 | ret = show_version(); 106 | goto out; 107 | case 'h': 108 | ret = 0; 109 | /* Fall through */ 110 | case '?': 111 | default: 112 | usage(ret ? EXIT_FAILURE : EXIT_SUCCESS); 113 | goto out; 114 | } 115 | 116 | if (optind == argc - 1) { 117 | name = g_strdup(argv[optind]); 118 | } else { 119 | usage(ret ? EXIT_FAILURE : EXIT_SUCCESS); 120 | goto out; 121 | } 122 | 123 | if (!usm_user_name(name, strchr(name, 0x00))) { 124 | pr_err("Invalid user name `%s'\n", name); 125 | goto out; 126 | } 127 | 128 | if (!pwddb) 129 | pwddb = g_strdup(PATH_PWDDB); 130 | if (!smbconf) 131 | smbconf = g_strdup(PATH_SMBCONF); 132 | 133 | ret = load_config(pwddb, smbconf); 134 | if (ret) 135 | goto out; 136 | 137 | if (!command) { 138 | struct ksmbd_user *user = usm_lookup_user(name); 139 | 140 | if (user) { 141 | put_ksmbd_user(user); 142 | command = command_update_user; 143 | } else { 144 | command = command_add_user; 145 | } 146 | } 147 | 148 | ret = command(pwddb, name, password); 149 | pwddb = name = password = NULL; 150 | if (ret) 151 | goto out; 152 | 153 | if (cp_parse_lock()) { 154 | pr_info("Ignored lock file\n"); 155 | goto out; 156 | } 157 | 158 | if (kill(global_conf.pid, SIGHUP) < 0) { 159 | pr_debug("Can't send SIGHUP to PID %d: %m\n", 160 | global_conf.pid); 161 | goto out; 162 | } 163 | 164 | pr_info("Notified mountd\n"); 165 | out: 166 | remove_config(); 167 | return ret ? EXIT_FAILURE : EXIT_SUCCESS; 168 | } 169 | -------------------------------------------------------------------------------- /addshare/addshare.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * Copyright (C) 2019 Samsung Electronics Co., Ltd. 4 | * 5 | * linux-cifsd-devel@lists.sourceforge.net 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "config_parser.h" 21 | #include "tools.h" 22 | #include "management/share.h" 23 | #include "management/user.h" 24 | #include "linux/ksmbd_server.h" 25 | #include "share_admin.h" 26 | 27 | static void usage(int status) 28 | { 29 | printf( 30 | "Usage: ksmbd.addshare [-v] [-C CONF] [-P PWDDB] [-a | -u | -d] [-o OPT]... SHARE\n"); 31 | 32 | if (status != EXIT_SUCCESS) 33 | printf("Try `ksmbd.addshare --help' for more information.\n"); 34 | else 35 | printf( 36 | "\n" 37 | "If neither `-a', `-u', nor `-d' is given, either add or update SHARE.\n" 38 | "SHARE must be UTF-8 and [1, " STR(KSMBD_REQ_MAX_SHARE_NAME) ") bytes.\n" 39 | "SHARE is case-insensitive.\n" 40 | "\n" 41 | " -a, --add add SHARE to configuration file\n" 42 | " -u, --update update SHARE in configuration file\n" 43 | " -d, --delete delete SHARE from configuration file\n" 44 | " -o, --option=OPT use OPT as share parameter instead of prompting;\n" 45 | " this option can be given multiple times\n" 46 | " -C, --config=CONF use CONF as configuration file instead of\n" 47 | " `" PATH_SMBCONF "'\n" 48 | " -P, --pwddb=PWDDB use PWDDB as user database instead of\n" 49 | " `" PATH_PWDDB "'\n" 50 | " -v, --verbose be verbose\n" 51 | " -V, --version output version information and exit\n" 52 | " -h, --help display this help and exit\n" 53 | "\n" 54 | "See ksmbd.addshare(8) for more details.\n"); 55 | } 56 | 57 | static const struct option opts[] = { 58 | {"add", no_argument, NULL, 'a' }, 59 | {"update", no_argument, NULL, 'u' }, 60 | {"delete", no_argument, NULL, 'd' }, 61 | {"option", required_argument, NULL, 'o' }, 62 | {"config", required_argument, NULL, 'C' }, 63 | {"pwddb", required_argument, NULL, 'P' }, 64 | {"verbose", no_argument, NULL, 'v' }, 65 | {"version", no_argument, NULL, 'V' }, 66 | {"help", no_argument, NULL, 'h' }, 67 | {NULL, 0, NULL, 0 } 68 | }; 69 | 70 | int addshare_main(int argc, char **argv) 71 | { 72 | int ret = -EINVAL; 73 | g_autofree char *smbconf = NULL, *name = NULL, *pwddb = NULL; 74 | g_auto(GStrv) options = NULL; 75 | g_autoptr(GPtrArray) __options = 76 | g_ptr_array_new_with_free_func(g_free); 77 | command_fn *command = NULL; 78 | int c; 79 | 80 | while ((c = getopt_long(argc, argv, "audo:C:P:vVh", opts, NULL)) != EOF) 81 | switch (c) { 82 | case 'a': 83 | command = command_add_share; 84 | break; 85 | case 'u': 86 | command = command_update_share; 87 | break; 88 | case 'd': 89 | command = command_delete_share; 90 | break; 91 | case 'o': 92 | gptrarray_printf(__options, "%s", optarg); 93 | break; 94 | case 'C': 95 | g_free(smbconf); 96 | smbconf = g_strdup(optarg); 97 | break; 98 | case 'P': 99 | g_free(pwddb); 100 | pwddb = g_strdup(optarg); 101 | break; 102 | case 'v': 103 | set_log_level(PR_DEBUG); 104 | break; 105 | case 'V': 106 | ret = show_version(); 107 | goto out; 108 | case 'h': 109 | ret = 0; 110 | /* Fall through */ 111 | case '?': 112 | default: 113 | usage(ret ? EXIT_FAILURE : EXIT_SUCCESS); 114 | goto out; 115 | } 116 | 117 | options = gptrarray_to_strv(__options); 118 | __options = NULL; 119 | 120 | if (optind == argc - 1) { 121 | name = g_strdup(argv[optind]); 122 | } else { 123 | usage(ret ? EXIT_FAILURE : EXIT_SUCCESS); 124 | goto out; 125 | } 126 | 127 | if (!shm_share_name(name, strchr(name, 0x00))) { 128 | pr_err("Invalid share name `%s'\n", name); 129 | goto out; 130 | } 131 | 132 | if (!pwddb) 133 | pwddb = g_strdup(PATH_PWDDB); 134 | if (!smbconf) 135 | smbconf = g_strdup(PATH_SMBCONF); 136 | 137 | ret = load_config(pwddb, smbconf); 138 | if (ret) 139 | goto out; 140 | 141 | if (!command) { 142 | if (g_hash_table_lookup(parser.groups, name)) 143 | command = command_update_share; 144 | else 145 | command = command_add_share; 146 | } 147 | 148 | ret = command(smbconf, name, options); 149 | smbconf = name = (char *)(options = NULL); 150 | if (ret) 151 | goto out; 152 | 153 | if (cp_parse_lock()) { 154 | pr_info("Ignored lock file\n"); 155 | goto out; 156 | } 157 | 158 | if (kill(global_conf.pid, SIGHUP) < 0) { 159 | pr_debug("Can't send SIGHUP to PID %d: %m\n", 160 | global_conf.pid); 161 | goto out; 162 | } 163 | 164 | pr_info("Notified mountd\n"); 165 | out: 166 | remove_config(); 167 | return ret ? EXIT_FAILURE : EXIT_SUCCESS; 168 | } 169 | -------------------------------------------------------------------------------- /include/management/share.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /* 3 | * Copyright (C) 2018 Samsung Electronics Co., Ltd. 4 | * 5 | * linux-cifsd-devel@lists.sourceforge.net 6 | */ 7 | 8 | #ifndef __MANAGEMENT_SHARE_H__ 9 | #define __MANAGEMENT_SHARE_H__ 10 | 11 | #include 12 | 13 | 14 | enum share_users { 15 | /* Admin users */ 16 | KSMBD_SHARE_ADMIN_USERS_MAP = 0, 17 | /* Valid users */ 18 | KSMBD_SHARE_VALID_USERS_MAP, 19 | /* Invalid users */ 20 | KSMBD_SHARE_INVALID_USERS_MAP, 21 | /* Read-only users */ 22 | KSMBD_SHARE_READ_LIST_MAP, 23 | /* Read/Write access to a read-only share */ 24 | KSMBD_SHARE_WRITE_LIST_MAP, 25 | KSMBD_SHARE_USERS_MAX, 26 | }; 27 | 28 | enum share_hosts { 29 | KSMBD_SHARE_HOSTS_ALLOW_MAP = 0, 30 | KSMBD_SHARE_HOSTS_DENY_MAP, 31 | KSMBD_SHARE_HOSTS_MAX, 32 | }; 33 | 34 | #define KSMBD_SHARE_INVALID_UID ((__u16)-1) 35 | #define KSMBD_SHARE_INVALID_GID ((__u16)-1) 36 | 37 | struct ksmbd_share { 38 | char *name; 39 | char *path; 40 | 41 | int max_connections; 42 | int num_connections; 43 | 44 | GRWLock update_lock; 45 | int ref_count; 46 | 47 | unsigned short create_mask; 48 | unsigned short directory_mask; 49 | unsigned short force_create_mode; 50 | unsigned short force_directory_mode; 51 | unsigned short force_uid; 52 | unsigned short force_gid; 53 | 54 | int flags; 55 | int state; 56 | 57 | char *veto_list; 58 | int veto_list_sz; 59 | 60 | char *guest_account; 61 | 62 | GHashTable *maps[KSMBD_SHARE_USERS_MAX]; 63 | /* 64 | * FIXME 65 | * We need to support IP ranges, netmasks, etc. 66 | * This is just a silly hostname matching, hence 67 | * these two are not in ->maps[]. 68 | */ 69 | GHashTable *hosts_allow_map; 70 | /* Deny access */ 71 | GHashTable *hosts_deny_map; 72 | 73 | /* One lock to rule them all [as of now] */ 74 | GRWLock maps_lock; 75 | 76 | char *comment; 77 | }; 78 | 79 | /* 80 | * WARNING: 81 | * 82 | * Add new entries only before to the bottom, right before 83 | * KSMBD_SHARE_CONF_MAX. See SHARE_CONF comment. 84 | * 85 | */ 86 | enum KSMBD_SHARE_CONF { 87 | KSMBD_SHARE_CONF_COMMENT = 0, 88 | KSMBD_SHARE_CONF_PATH, 89 | KSMBD_SHARE_CONF_GUEST_OK, 90 | KSMBD_SHARE_CONF_GUEST_ACCOUNT, 91 | KSMBD_SHARE_CONF_READ_ONLY, 92 | KSMBD_SHARE_CONF_BROWSEABLE = 5, 93 | KSMBD_SHARE_CONF_WRITE_OK, 94 | KSMBD_SHARE_CONF_WRITEABLE, 95 | KSMBD_SHARE_CONF_STORE_DOS_ATTRIBUTES, 96 | KSMBD_SHARE_CONF_OPLOCKS, 97 | KSMBD_SHARE_CONF_CREATE_MASK = 10, 98 | KSMBD_SHARE_CONF_DIRECTORY_MASK, 99 | KSMBD_SHARE_CONF_FORCE_CREATE_MODE, 100 | KSMBD_SHARE_CONF_FORCE_DIRECTORY_MODE, 101 | KSMBD_SHARE_CONF_FORCE_GROUP, 102 | KSMBD_SHARE_CONF_FORCE_USER = 15, 103 | KSMBD_SHARE_CONF_HIDE_DOT_FILES, 104 | KSMBD_SHARE_CONF_VALID_USERS, 105 | KSMBD_SHARE_CONF_INVALID_USERS, 106 | KSMBD_SHARE_CONF_READ_LIST, 107 | KSMBD_SHARE_CONF_WRITE_LIST = 20, 108 | KSMBD_SHARE_CONF_ADMIN_USERS, 109 | KSMBD_SHARE_CONF_HOSTS_ALLOW, 110 | KSMBD_SHARE_CONF_HOSTS_DENY, 111 | KSMBD_SHARE_CONF_MAX_CONNECTIONS, 112 | KSMBD_SHARE_CONF_VETO_FILES = 25, 113 | KSMBD_SHARE_CONF_INHERIT_OWNER, 114 | KSMBD_SHARE_CONF_FOLLOW_SYMLINKS, 115 | KSMBD_SHARE_CONF_VFS_OBJECTS, 116 | KSMBD_SHARE_CONF_WRITABLE, 117 | KSMBD_SHARE_CONF_CROSSMNT = 30, 118 | KSMBD_SHARE_CONF_MAX 119 | }; 120 | 121 | extern const char *KSMBD_SHARE_CONF[KSMBD_SHARE_CONF_MAX]; 122 | extern const char *KSMBD_SHARE_DEFCONF[KSMBD_SHARE_CONF_MAX]; 123 | 124 | #define KSMBD_SHARE_CONF_IS_GLOBAL(c) \ 125 | ((c) == KSMBD_SHARE_CONF_GUEST_ACCOUNT || \ 126 | (c) == KSMBD_SHARE_CONF_MAX_CONNECTIONS) 127 | 128 | #define KSMBD_SHARE_CONF_IS_BROKEN(c) \ 129 | ((c) == KSMBD_SHARE_CONF_ADMIN_USERS || \ 130 | (c) == KSMBD_SHARE_CONF_HOSTS_ALLOW || \ 131 | (c) == KSMBD_SHARE_CONF_HOSTS_DENY) 132 | 133 | int shm_share_name(char *name, char *p); 134 | int shm_share_config(const char *k, enum KSMBD_SHARE_CONF c); 135 | 136 | static inline void set_share_flag(struct ksmbd_share *share, int flag) 137 | { 138 | share->flags |= flag; 139 | } 140 | 141 | static inline void clear_share_flag(struct ksmbd_share *share, int flag) 142 | { 143 | share->flags &= ~flag; 144 | } 145 | 146 | static inline int test_share_flag(struct ksmbd_share *share, int flag) 147 | { 148 | return share->flags & flag; 149 | } 150 | 151 | struct ksmbd_share *get_ksmbd_share(struct ksmbd_share *share); 152 | void put_ksmbd_share(struct ksmbd_share *share); 153 | struct ksmbd_share *shm_lookup_share(char *name); 154 | 155 | struct smbconf_group; 156 | int shm_add_new_share(struct smbconf_group *group); 157 | 158 | void shm_remove_all_shares(void); 159 | 160 | void shm_destroy(void); 161 | unsigned int shm_share_name_hash(const char *name); 162 | int shm_share_name_equal(const char *lname, const char *rname); 163 | void shm_init(void); 164 | 165 | int shm_lookup_users_map(struct ksmbd_share *share, 166 | enum share_users map, 167 | char *name); 168 | 169 | int shm_lookup_hosts_map(struct ksmbd_share *share, 170 | enum share_hosts map, 171 | char *host); 172 | 173 | int shm_open_connection(struct ksmbd_share *share); 174 | int shm_close_connection(struct ksmbd_share *share); 175 | 176 | typedef void (*share_cb)(struct ksmbd_share *share, void *data); 177 | void shm_iter_shares(share_cb cb, void *data); 178 | 179 | struct ksmbd_share_config_response; 180 | 181 | int shm_share_config_payload_size(struct ksmbd_share *share); 182 | int shm_handle_share_config_request(struct ksmbd_share *share, 183 | struct ksmbd_share_config_response *resp); 184 | 185 | #endif /* __MANAGEMENT_SHARE_H__ */ 186 | -------------------------------------------------------------------------------- /tools/management/session.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * Copyright (C) 2018 Samsung Electronics Co., Ltd. 4 | * 5 | * linux-cifsd-devel@lists.sourceforge.net 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "linux/ksmbd_server.h" 13 | #include "management/session.h" 14 | #include "management/tree_conn.h" 15 | #include "management/user.h" 16 | #include "tools.h" 17 | 18 | static GHashTable *sessions_table; 19 | static GRWLock sessions_table_lock; 20 | 21 | static void kill_ksmbd_session(struct ksmbd_session *sess) 22 | { 23 | g_list_free_full(sess->tree_conns, (GDestroyNotify)tcm_tree_conn_free); 24 | g_rw_lock_clear(&sess->update_lock); 25 | g_free(sess); 26 | } 27 | 28 | static struct ksmbd_session *new_ksmbd_session(unsigned long long id, 29 | struct ksmbd_user *user) 30 | { 31 | struct ksmbd_session *sess; 32 | 33 | sess = g_try_malloc0(sizeof(struct ksmbd_session)); 34 | if (!sess) 35 | return NULL; 36 | 37 | g_rw_lock_init(&sess->update_lock); 38 | sess->ref_counter = 1; 39 | sess->id = id; 40 | sess->user = user; 41 | return sess; 42 | } 43 | 44 | static void sm_clear_sessions(void) 45 | { 46 | struct ksmbd_session *sess; 47 | GHashTableIter iter; 48 | 49 | ghash_for_each(sess, sessions_table, iter) 50 | kill_ksmbd_session(sess); 51 | } 52 | 53 | static int __sm_remove_session(struct ksmbd_session *sess) 54 | { 55 | int ret = -EINVAL; 56 | 57 | g_rw_lock_writer_lock(&sessions_table_lock); 58 | if (g_hash_table_remove(sessions_table, &sess->id)) 59 | ret = 0; 60 | g_rw_lock_writer_unlock(&sessions_table_lock); 61 | 62 | if (!ret) 63 | kill_ksmbd_session(sess); 64 | return ret; 65 | } 66 | 67 | static struct ksmbd_session *__get_session(struct ksmbd_session *sess) 68 | { 69 | struct ksmbd_session *ret = NULL; 70 | 71 | g_rw_lock_writer_lock(&sess->update_lock); 72 | if (sess->ref_counter != 0) { 73 | sess->ref_counter++; 74 | ret = sess; 75 | } else { 76 | ret = NULL; 77 | } 78 | g_rw_lock_writer_unlock(&sess->update_lock); 79 | return ret; 80 | } 81 | 82 | static void __put_session(struct ksmbd_session *sess) 83 | { 84 | int drop = 0; 85 | 86 | g_rw_lock_writer_lock(&sess->update_lock); 87 | sess->ref_counter--; 88 | drop = !sess->ref_counter; 89 | g_rw_lock_writer_unlock(&sess->update_lock); 90 | 91 | if (drop) 92 | __sm_remove_session(sess); 93 | } 94 | 95 | static struct ksmbd_session *__sm_lookup_session(unsigned long long id) 96 | { 97 | return g_hash_table_lookup(sessions_table, &id); 98 | } 99 | 100 | static struct ksmbd_session *sm_lookup_session(unsigned long long id) 101 | { 102 | struct ksmbd_session *sess; 103 | 104 | g_rw_lock_reader_lock(&sessions_table_lock); 105 | sess = __sm_lookup_session(id); 106 | if (sess) 107 | sess = __get_session(sess); 108 | g_rw_lock_reader_unlock(&sessions_table_lock); 109 | return sess; 110 | } 111 | 112 | int sm_handle_tree_connect(unsigned long long id, 113 | struct ksmbd_user *user, 114 | struct ksmbd_tree_conn *tree_conn) 115 | { 116 | struct ksmbd_session *sess, *lookup; 117 | 118 | retry: 119 | sess = sm_lookup_session(id); 120 | if (!sess) { 121 | sess = new_ksmbd_session(id, user); 122 | if (!sess) 123 | return -EINVAL; 124 | 125 | g_rw_lock_writer_lock(&sessions_table_lock); 126 | lookup = __sm_lookup_session(id); 127 | if (lookup) 128 | lookup = __get_session(lookup); 129 | if (lookup) { 130 | kill_ksmbd_session(sess); 131 | sess = lookup; 132 | } 133 | if (!g_hash_table_insert(sessions_table, &(sess->id), sess)) { 134 | kill_ksmbd_session(sess); 135 | sess = NULL; 136 | } 137 | g_rw_lock_writer_unlock(&sessions_table_lock); 138 | 139 | if (!sess) 140 | goto retry; 141 | } 142 | 143 | g_rw_lock_writer_lock(&sess->update_lock); 144 | sess->tree_conns = g_list_insert(sess->tree_conns, tree_conn, -1); 145 | g_rw_lock_writer_unlock(&sess->update_lock); 146 | return 0; 147 | } 148 | 149 | int sm_check_sessions_capacity(unsigned long long id) 150 | { 151 | int ret = 0; 152 | struct ksmbd_session *sess; 153 | 154 | sess = sm_lookup_session(id); 155 | if (sess) { 156 | __put_session(sess); 157 | return ret; 158 | } 159 | 160 | if (g_atomic_int_add(&global_conf.sessions_cap, -1) < 1) { 161 | ret = -EINVAL; 162 | g_atomic_int_inc(&global_conf.sessions_cap); 163 | } 164 | return ret; 165 | } 166 | 167 | static int lookup_tree_conn(const struct ksmbd_tree_conn *tree_conn, 168 | const struct ksmbd_tree_conn *dummy) 169 | { 170 | return !(tree_conn->id == dummy->id); 171 | } 172 | 173 | int sm_handle_tree_disconnect(unsigned long long sess_id, 174 | unsigned long long tree_conn_id) 175 | { 176 | struct ksmbd_tree_conn dummy; 177 | struct ksmbd_session *sess; 178 | GList *tc_list; 179 | 180 | sess = sm_lookup_session(sess_id); 181 | if (!sess) 182 | return 0; 183 | 184 | g_atomic_int_inc(&global_conf.sessions_cap); 185 | g_rw_lock_writer_lock(&sess->update_lock); 186 | dummy.id = tree_conn_id; 187 | tc_list = g_list_find_custom(sess->tree_conns, 188 | &dummy, 189 | (GCompareFunc)lookup_tree_conn); 190 | if (tc_list) { 191 | struct ksmbd_tree_conn *tree_conn; 192 | 193 | tree_conn = (struct ksmbd_tree_conn *)tc_list->data; 194 | sess->tree_conns = g_list_remove(sess->tree_conns, tree_conn); 195 | sess->ref_counter--; 196 | tcm_tree_conn_free(tree_conn); 197 | } 198 | g_rw_lock_writer_unlock(&sess->update_lock); 199 | 200 | __put_session(sess); 201 | return 0; 202 | } 203 | 204 | void sm_destroy(void) 205 | { 206 | if (sessions_table) { 207 | sm_clear_sessions(); 208 | g_hash_table_destroy(sessions_table); 209 | sessions_table = NULL; 210 | } 211 | } 212 | 213 | void sm_init(void) 214 | { 215 | if (!sessions_table) 216 | sessions_table = g_hash_table_new(g_int64_hash, g_int64_equal); 217 | } 218 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ([2.68]) 2 | 3 | m4_define([ksmbd_tools_version], m4_esyscmd_s([ 4 | exec awk '/define KSMBD_TOOLS_VERSION / { gsub(/"/,"",$3); printf "%s", $3 }' include/version.h 5 | ])) 6 | 7 | AC_INIT([ksmbd-tools], 8 | [ksmbd_tools_version], 9 | [linkinjeon@kernel.org], 10 | [ksmbd-tools], 11 | [https://github.com/cifsd-team/ksmbd-tools]) 12 | 13 | AC_CONFIG_SRCDIR([config.h.in]) 14 | AC_CONFIG_HEADER([config.h]) 15 | AC_CONFIG_MACRO_DIR([m4]) 16 | AC_CONFIG_AUX_DIR([build-aux]) 17 | AM_INIT_AUTOMAKE([foreign tar-pax subdir-objects]) 18 | 19 | AC_SUBST([ksmbd_tools_version], ksmbd_tools_version) 20 | 21 | AC_LANG([C]) 22 | AC_PROG_CC 23 | AC_PROG_CC_STDC 24 | AM_SILENT_RULES([yes]) 25 | AC_PROG_LIBTOOL 26 | AC_PROG_SED 27 | AC_PROG_MKDIR_P 28 | AC_PROG_LN_S 29 | 30 | AC_SUBST([in_script], [[\ 31 | '$(SED) -e "s,[@]sbindir[@],$(sbindir),g" \ 32 | -e "s,[@]sysconfdir[@],$(sysconfdir),g" \ 33 | -e "s,[@]runstatedir[@],$(runstatedir),g" \ 34 | -e "s,[@]ksmbd_tools_version[@],$(ksmbd_tools_version),g"' 35 | ]]) 36 | 37 | AC_ARG_ENABLE([krb5], 38 | [AC_HELP_STRING([--enable-krb5], [Enable Kerberos 5 authentication @<:@default=no@:>@])], 39 | [enable_krb5=$enableval], 40 | [enable_krb5=no]) 41 | 42 | AS_IF([test "x$enable_krb5" != xno], [ 43 | PKG_CHECK_MODULES([LIBKRB5], [krb5]) 44 | 45 | save_CPPFLAGS=$CPPFLAGS 46 | CPPFLAGS="$CPPFLAGS $LIBKRB5_CFLAGS" 47 | AC_CHECK_HEADERS([krb5.h]) 48 | CPPFLAGS=$save_CPPFLAGS 49 | 50 | AS_IF([test "x$ac_cv_header_krb5_h" != xyes], [ 51 | AS_IF([test "x$enable_krb5" = xyes], [ 52 | AC_MSG_ERROR([krb5.h was not found.]) 53 | ], [ 54 | AC_MSG_WARN([krb5.h was not found, disabling Kerberos 5 support.]) 55 | enable_krb5=no 56 | ]) 57 | ]) 58 | ]) 59 | 60 | AC_ARG_WITH([rundir], 61 | [AC_HELP_STRING([--with-rundir=DIR], 62 | [Store modifiable per-process data in DIR @<:@LOCALSTATEDIR/run@:>@])], 63 | [with_rundir=$withval], 64 | [with_rundir=no]) 65 | 66 | AS_IF([test "x$with_rundir" = xno], [ 67 | AS_IF([test "x$runstatedir" = x], [ 68 | runstatedir='${localstatedir}/run' 69 | ], []) 70 | ], [ 71 | runstatedir=$with_rundir 72 | ]) 73 | 74 | AC_SUBST([runstatedir]) 75 | 76 | AC_ARG_WITH([systemdsystemunitdir], 77 | [AC_HELP_STRING([--with-systemdsystemunitdir@<:@=DIR@:>@], 78 | [Install systemd unit file to DIR (query pkg-config by default)])], 79 | [with_systemdsystemunitdir=$withval], 80 | [with_systemdsystemunitdir=yes]) 81 | 82 | AS_IF([test "x$with_systemdsystemunitdir" != xno], [ 83 | AS_IF([test "x$with_systemdsystemunitdir" = xyes], [ 84 | PKG_CHECK_VAR([systemdsystemunitdir], [systemd >= 245], [systemdsystemunitdir], [], []) 85 | ], [ 86 | systemdsystemunitdir=$with_systemdsystemunitdir 87 | ]) 88 | ]) 89 | 90 | AC_SUBST([systemdsystemunitdir]) 91 | 92 | save_LIBS=$LIBS 93 | LIBS= 94 | AC_SEARCH_LIBS([pthread_sigmask], [pthread], [], [ 95 | AC_MSG_ERROR([pthread was not found.]) 96 | ]) 97 | PTHREAD_LIBS=$LIBS 98 | LIBS=$save_LIBS 99 | 100 | AC_SUBST([PTHREAD_LIBS]) 101 | 102 | PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.58], [have_glib=yes], [have_glib=no]) 103 | AS_IF([test "x$have_glib" != xyes], [ 104 | AC_MSG_ERROR([glib (libglib2.0-dev or glib2-devel) was not found.]) 105 | ]) 106 | 107 | PKG_CHECK_MODULES([LIBNL], [libnl-3.0 >= 3.0 libnl-genl-3.0 >= 3.0], [have_libnl=yes], [have_libnl=no]) 108 | AS_IF([test "x$have_libnl" != xyes], [ 109 | AC_MSG_ERROR([libnl (libnl-3-dev or libnl3-devel) and libnl-genl (libnl-genl-3-dev) were not found.]) 110 | ]) 111 | 112 | AS_IF([test "x$enable_krb5" != xno], [ 113 | AC_DEFINE([CONFIG_KRB5], [], [Define if Kerberos 5 authentication is supported.]) 114 | 115 | save_LIBS=$LIBS 116 | LIBS="$LIBS $LIBKRB5_LIBS" 117 | AC_CHECK_FUNCS([krb5_auth_con_getrecvsubkey]) 118 | LIBS=$save_LIBS 119 | 120 | save_CPPFLAGS=$CPPFLAGS 121 | CPPFLAGS="$CPPFLAGS $LIBKRB5_CFLAGS" 122 | AC_CHECK_MEMBER([krb5_keyblock.keyvalue], 123 | [ac_cv_have_krb5_keyblock_keyvalue=yes], 124 | [ac_cv_have_krb5_keyblock_keyvalue=no], 125 | [[#include ]]) 126 | AC_CHECK_MEMBER([krb5_authenticator.client], 127 | [ac_cv_have_krb5_authenticator_client=yes], 128 | [ac_cv_have_krb5_authenticator_client=no], 129 | [[#include ]]) 130 | AC_CACHE_CHECK([for krb5_authenticator** parameter in krb5_auth_con_getauthenticator], 131 | [ac_cv_have_krb5_auth_con_getauthenticator_double_pointer], 132 | [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ 133 | #include 134 | krb5_error_code krb5_auth_con_getauthenticator(krb5_context, krb5_auth_context, krb5_authenticator**); 135 | ]], [])], 136 | [ac_cv_have_krb5_auth_con_getauthenticator_double_pointer=yes], 137 | [ac_cv_have_krb5_auth_con_getauthenticator_double_pointer=no])]) 138 | CPPFLAGS=$save_CPPFLAGS 139 | 140 | AS_IF([test "x$ac_cv_have_krb5_keyblock_keyvalue" = xyes], [ 141 | AC_DEFINE([HAVE_KRB5_KEYBLOCK_KEYVALUE], [], 142 | [Define if krb5_keyblock has keyvalue member.]) 143 | ]) 144 | AS_IF([test "x$ac_cv_have_krb5_authenticator_client" = xyes], [ 145 | AC_DEFINE([HAVE_KRB5_AUTHENTICATOR_CLIENT], [], 146 | [Define if krb5_authenticator has client member.]) 147 | ]) 148 | AS_IF([test "x$ac_cv_have_krb5_auth_con_getauthenticator_double_pointer" = xyes], [ 149 | AC_DEFINE([HAVE_KRB5_AUTH_CON_GETAUTHENTICATOR_DOUBLE_POINTER], [], 150 | [Define if krb5_auth_con_getauthenticator has krb5_authenticator** parameter.]) 151 | ]) 152 | ]) 153 | 154 | AM_CONDITIONAL(HAVE_LIBKRB5, [test "x$enable_krb5" != xno]) 155 | 156 | AC_CONFIG_FILES([ 157 | Makefile 158 | addshare/Makefile 159 | adduser/Makefile 160 | control/Makefile 161 | mountd/Makefile 162 | tools/Makefile 163 | ]) 164 | 165 | AC_OUTPUT 166 | -------------------------------------------------------------------------------- /adduser/md4_hash.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * Cryptographic API. 4 | * 5 | * MD4 Message Digest Algorithm (RFC1320). 6 | * 7 | * Implementation derived from Andrew Tridgell and Steve French's 8 | * CIFS MD4 implementation, and the cryptoapi implementation 9 | * originally based on the public domain implementation written 10 | * by Colin Plumb in 1993. 11 | * 12 | * Copyright (c) Andrew Tridgell 1997-1998. 13 | * Modified by Steve French (sfrench@us.ibm.com) 2002 14 | * Modified by Namjae Jeon (namjae.jeon@samsung.com) 2015 15 | * Copyright (c) Cryptoapi developers. 16 | * Copyright (c) 2002 David S. Miller (davem@redhat.com) 17 | * Copyright (c) 2002 James Morris 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #define u8 unsigned char 26 | #define u32 unsigned int 27 | #define u64 unsigned long long 28 | 29 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 30 | 31 | static inline u32 lshift(u32 x, unsigned int s) 32 | { 33 | x &= 0xFFFFFFFF; 34 | return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s)); 35 | } 36 | 37 | static inline u32 F(u32 x, u32 y, u32 z) 38 | { 39 | return (x & y) | ((~x) & z); 40 | } 41 | 42 | static inline u32 G(u32 x, u32 y, u32 z) 43 | { 44 | return (x & y) | (x & z) | (y & z); 45 | } 46 | 47 | static inline u32 H(u32 x, u32 y, u32 z) 48 | { 49 | return x ^ y ^ z; 50 | } 51 | 52 | static inline void ROUND1(u32 *a, u32 b, u32 c, 53 | u32 d, u32 k, u32 s) 54 | { 55 | *a = lshift(*a + F(b, c, d) + k, s); 56 | } 57 | 58 | static inline void ROUND2(u32 *a, u32 b, u32 c, 59 | u32 d, u32 k, u32 s) 60 | { 61 | *a = lshift(*a + G(b, c, d) + k + (u32)0x5A827999, s); 62 | } 63 | 64 | static inline void ROUND3(u32 *a, u32 b, u32 c, 65 | u32 d, u32 k, u32 s) 66 | { 67 | *a = lshift(*a + H(b, c, d) + k + (u32)0x6ED9EBA1, s); 68 | } 69 | 70 | /* XXX: this stuff can be optimized */ 71 | static inline void le32_to_cpu_array(u32 *buf, unsigned int words) 72 | { 73 | while (words--) { 74 | __le32_to_cpus(buf); 75 | buf++; 76 | } 77 | } 78 | 79 | static inline void cpu_to_le32_array(u32 *buf, unsigned int words) 80 | { 81 | while (words--) { 82 | __cpu_to_le32s(buf); 83 | buf++; 84 | } 85 | } 86 | 87 | static void md4_transform(u32 *hash, u32 const *in) 88 | { 89 | u32 a, b, c, d; 90 | 91 | a = hash[0]; 92 | b = hash[1]; 93 | c = hash[2]; 94 | d = hash[3]; 95 | 96 | ROUND1(&a, b, c, d, in[0], 3); 97 | ROUND1(&d, a, b, c, in[1], 7); 98 | ROUND1(&c, d, a, b, in[2], 11); 99 | ROUND1(&b, c, d, a, in[3], 19); 100 | ROUND1(&a, b, c, d, in[4], 3); 101 | ROUND1(&d, a, b, c, in[5], 7); 102 | ROUND1(&c, d, a, b, in[6], 11); 103 | ROUND1(&b, c, d, a, in[7], 19); 104 | ROUND1(&a, b, c, d, in[8], 3); 105 | ROUND1(&d, a, b, c, in[9], 7); 106 | ROUND1(&c, d, a, b, in[10], 11); 107 | ROUND1(&b, c, d, a, in[11], 19); 108 | ROUND1(&a, b, c, d, in[12], 3); 109 | ROUND1(&d, a, b, c, in[13], 7); 110 | ROUND1(&c, d, a, b, in[14], 11); 111 | ROUND1(&b, c, d, a, in[15], 19); 112 | 113 | ROUND2(&a, b, c, d, in[0], 3); 114 | ROUND2(&d, a, b, c, in[4], 5); 115 | ROUND2(&c, d, a, b, in[8], 9); 116 | ROUND2(&b, c, d, a, in[12], 13); 117 | ROUND2(&a, b, c, d, in[1], 3); 118 | ROUND2(&d, a, b, c, in[5], 5); 119 | ROUND2(&c, d, a, b, in[9], 9); 120 | ROUND2(&b, c, d, a, in[13], 13); 121 | ROUND2(&a, b, c, d, in[2], 3); 122 | ROUND2(&d, a, b, c, in[6], 5); 123 | ROUND2(&c, d, a, b, in[10], 9); 124 | ROUND2(&b, c, d, a, in[14], 13); 125 | ROUND2(&a, b, c, d, in[3], 3); 126 | ROUND2(&d, a, b, c, in[7], 5); 127 | ROUND2(&c, d, a, b, in[11], 9); 128 | ROUND2(&b, c, d, a, in[15], 13); 129 | 130 | ROUND3(&a, b, c, d, in[0], 3); 131 | ROUND3(&d, a, b, c, in[8], 9); 132 | ROUND3(&c, d, a, b, in[4], 11); 133 | ROUND3(&b, c, d, a, in[12], 15); 134 | ROUND3(&a, b, c, d, in[2], 3); 135 | ROUND3(&d, a, b, c, in[10], 9); 136 | ROUND3(&c, d, a, b, in[6], 11); 137 | ROUND3(&b, c, d, a, in[14], 15); 138 | ROUND3(&a, b, c, d, in[1], 3); 139 | ROUND3(&d, a, b, c, in[9], 9); 140 | ROUND3(&c, d, a, b, in[5], 11); 141 | ROUND3(&b, c, d, a, in[13], 15); 142 | ROUND3(&a, b, c, d, in[3], 3); 143 | ROUND3(&d, a, b, c, in[11], 9); 144 | ROUND3(&c, d, a, b, in[7], 11); 145 | ROUND3(&b, c, d, a, in[15], 15); 146 | 147 | hash[0] += a; 148 | hash[1] += b; 149 | hash[2] += c; 150 | hash[3] += d; 151 | } 152 | 153 | static inline void md4_transform_helper(struct md4_ctx *ctx) 154 | { 155 | le32_to_cpu_array(ctx->block, ARRAY_SIZE(ctx->block)); 156 | md4_transform(ctx->hash, ctx->block); 157 | } 158 | 159 | void md4_init(struct md4_ctx *mctx) 160 | { 161 | mctx->hash[0] = 0x67452301; 162 | mctx->hash[1] = 0xefcdab89; 163 | mctx->hash[2] = 0x98badcfe; 164 | mctx->hash[3] = 0x10325476; 165 | mctx->byte_count = 0; 166 | } 167 | 168 | void md4_update(struct md4_ctx *mctx, const u8 *data, unsigned int len) 169 | { 170 | const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f); 171 | 172 | mctx->byte_count += len; 173 | 174 | if (avail > len) { 175 | memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), 176 | data, len); 177 | return; 178 | } 179 | 180 | memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), 181 | data, avail); 182 | 183 | md4_transform_helper(mctx); 184 | data += avail; 185 | len -= avail; 186 | 187 | while (len >= sizeof(mctx->block)) { 188 | memcpy(mctx->block, data, sizeof(mctx->block)); 189 | md4_transform_helper(mctx); 190 | data += sizeof(mctx->block); 191 | len -= sizeof(mctx->block); 192 | } 193 | 194 | memcpy(mctx->block, data, len); 195 | } 196 | 197 | void md4_final(struct md4_ctx *mctx, u8 *out) 198 | { 199 | const unsigned int offset = mctx->byte_count & 0x3f; 200 | char *p = (char *)mctx->block + offset; 201 | int padding = 56 - (offset + 1); 202 | 203 | *p++ = 0x80; 204 | if (padding < 0) { 205 | memset(p, 0x00, padding + sizeof(u64)); 206 | md4_transform_helper(mctx); 207 | p = (char *)mctx->block; 208 | padding = 56; 209 | } 210 | 211 | memset(p, 0, padding); 212 | mctx->block[14] = mctx->byte_count << 3; 213 | mctx->block[15] = mctx->byte_count >> 29; 214 | le32_to_cpu_array(mctx->block, (sizeof(mctx->block) - 215 | sizeof(u64)) / sizeof(u32)); 216 | md4_transform(mctx->hash, mctx->block); 217 | cpu_to_le32_array(mctx->hash, ARRAY_SIZE(mctx->hash)); 218 | memcpy(out, mctx->hash, sizeof(mctx->hash)); 219 | memset(mctx, 0, sizeof(*mctx)); 220 | } 221 | -------------------------------------------------------------------------------- /mountd/rpc_wkssvc.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * Copyright (C) 2018 Samsung Electronics Co., Ltd. 4 | * 5 | * linux-cifsd-devel@lists.sourceforge.net 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #define WKSSVC_NETWKSTA_GET_INFO (0) 21 | 22 | #define WKSSVC_PLATFORM_ID_DOS 300 23 | #define WKSSVC_PLATFORM_ID_OS2 400 24 | #define WKSSVC_PLATFORM_ID_NT 500 25 | #define WKSSVC_PLATFORM_ID_OSF 600 26 | #define WKSSVC_PLATFORM_ID_VMS 700 27 | 28 | #define WKSSVC_VERSION_MAJOR 0x2 29 | #define WKSSVC_VERSION_MINOR 0x1 30 | 31 | static int wkssvc_clear_headers(struct ksmbd_rpc_pipe *pipe, 32 | int status) 33 | { 34 | ndr_free_uniq_vstring_ptr(&pipe->dce->wi_req.server_name); 35 | return 0; 36 | } 37 | 38 | static int __netwksta_entry_rep_ctr100(struct ksmbd_dcerpc *dce, 39 | gpointer entry) 40 | { 41 | int ret = 0; 42 | 43 | /* srvsvc_PlatformId */ 44 | ret = ndr_write_int32(dce, WKSSVC_PLATFORM_ID_NT); 45 | if (ret) 46 | return ret; 47 | 48 | /* server_name */ 49 | dce->num_pointers++; 50 | ret = ndr_write_int32(dce, dce->num_pointers); /* ref pointer */ 51 | if (ret) 52 | return ret; 53 | 54 | /* domain_name */ 55 | dce->num_pointers++; 56 | ret = ndr_write_int32(dce, dce->num_pointers); /* ref pointer */ 57 | if (ret) 58 | return ret; 59 | 60 | /* version_major */ 61 | ret = ndr_write_int32(dce, WKSSVC_VERSION_MAJOR); 62 | if (ret) 63 | return ret; 64 | 65 | /* version_minor */ 66 | ret = ndr_write_int32(dce, WKSSVC_VERSION_MINOR); 67 | 68 | return ret; 69 | } 70 | 71 | static int __netwksta_entry_data_ctr100(struct ksmbd_dcerpc *dce, 72 | gpointer entry) 73 | { 74 | int ret = 0; 75 | 76 | /* 77 | * Umm... Hmm... Huh... 78 | */ 79 | ret = ndr_write_vstring(dce, STR_VAL(dce->wi_req.server_name)); 80 | if (ret) 81 | return ret; 82 | 83 | return ndr_write_vstring(dce, global_conf.work_group); 84 | } 85 | 86 | static int wkssvc_netwksta_get_info_return(struct ksmbd_rpc_pipe *pipe) 87 | { 88 | struct ksmbd_dcerpc *dce = pipe->dce; 89 | 90 | if (ndr_write_union_int32(dce, dce->wi_req.level)) 91 | return KSMBD_RPC_EBAD_DATA; 92 | 93 | if (dce->wi_req.level != 100) { 94 | pr_err("Unsupported wksta info level (read): %d\n", 95 | dce->wi_req.level); 96 | dce->entry_rep = NULL; 97 | return KSMBD_RPC_EINVALID_LEVEL; 98 | } 99 | 100 | if (dce->entry_rep(dce, NULL)) 101 | return KSMBD_RPC_EBAD_DATA; 102 | 103 | if (dce->entry_data(dce, NULL)) 104 | return KSMBD_RPC_EBAD_DATA; 105 | 106 | return KSMBD_RPC_OK; 107 | } 108 | 109 | static int wkssvc_netwksta_info_return(struct ksmbd_rpc_pipe *pipe) 110 | { 111 | struct ksmbd_dcerpc *dce = pipe->dce; 112 | int status = KSMBD_RPC_ENOTIMPLEMENTED; 113 | 114 | /* 115 | * Reserve space for response NDR header. We don't know yet if 116 | * the payload buffer is big enough. This will determine if we 117 | * can set DCERPC_PFC_FIRST_FRAG|DCERPC_PFC_LAST_FRAG or if we 118 | * will have a multi-part response. 119 | */ 120 | dce->offset = sizeof(struct dcerpc_header); 121 | dce->offset += sizeof(struct dcerpc_response_header); 122 | pipe->num_processed = 0; 123 | 124 | if (dce->wi_req.level == 100) { 125 | dce->entry_rep = __netwksta_entry_rep_ctr100; 126 | dce->entry_data = __netwksta_entry_data_ctr100; 127 | } else { 128 | pr_err("Unsupported wksta info level (write): %d\n", 129 | dce->wi_req.level); 130 | rpc_pipe_reset(pipe); 131 | } 132 | 133 | if (dce->req_hdr.opnum == WKSSVC_NETWKSTA_GET_INFO) 134 | status = wkssvc_netwksta_get_info_return(pipe); 135 | 136 | if (rpc_restricted_context(dce->rpc_req)) 137 | status = KSMBD_RPC_EACCESS_DENIED; 138 | 139 | wkssvc_clear_headers(pipe, status); 140 | 141 | /* 142 | * [out] DWORD Return value/code 143 | */ 144 | if (ndr_write_int32(dce, status)) 145 | return KSMBD_RPC_EBAD_DATA; 146 | 147 | if (dcerpc_write_headers(dce, status)) 148 | return KSMBD_RPC_EBAD_DATA; 149 | 150 | dce->rpc_resp->payload_sz = dce->offset; 151 | return KSMBD_RPC_OK; 152 | } 153 | 154 | static int 155 | wkssvc_netwksta_get_info_invoke(struct ksmbd_rpc_pipe *pipe, 156 | struct wkssvc_netwksta_info_request *hdr) 157 | { 158 | return KSMBD_RPC_OK; 159 | } 160 | 161 | static int 162 | wkssvc_parse_netwksta_info_req(struct ksmbd_dcerpc *dce, 163 | struct wkssvc_netwksta_info_request *hdr) 164 | { 165 | int val; 166 | 167 | if (ndr_read_uniq_vstring_ptr(dce, &hdr->server_name)) 168 | return -EINVAL; 169 | if (ndr_read_int32(dce, &val)) 170 | return -EINVAL; 171 | hdr->level = val; 172 | return 0; 173 | } 174 | 175 | static int wkssvc_netwksta_info_invoke(struct ksmbd_rpc_pipe *pipe) 176 | { 177 | struct ksmbd_dcerpc *dce = pipe->dce; 178 | int ret = KSMBD_RPC_ENOTIMPLEMENTED; 179 | 180 | if (wkssvc_parse_netwksta_info_req(dce, &dce->wi_req)) 181 | return KSMBD_RPC_EBAD_DATA; 182 | 183 | if (rpc_restricted_context(dce->rpc_req)) 184 | return KSMBD_RPC_OK; 185 | 186 | if (dce->req_hdr.opnum == WKSSVC_NETWKSTA_GET_INFO) 187 | ret = wkssvc_netwksta_get_info_invoke(pipe, &dce->wi_req); 188 | return ret; 189 | } 190 | 191 | static int wkssvc_invoke(struct ksmbd_rpc_pipe *pipe) 192 | { 193 | int ret = KSMBD_RPC_ENOTIMPLEMENTED; 194 | 195 | switch (pipe->dce->req_hdr.opnum) { 196 | case WKSSVC_NETWKSTA_GET_INFO: 197 | ret = wkssvc_netwksta_info_invoke(pipe); 198 | break; 199 | default: 200 | pr_debug("WKSSVC: unsupported INVOKE method %d\n", 201 | pipe->dce->req_hdr.opnum); 202 | break; 203 | } 204 | 205 | return ret; 206 | } 207 | 208 | static int wkssvc_return(struct ksmbd_rpc_pipe *pipe, 209 | struct ksmbd_rpc_command *resp, 210 | int max_resp_sz) 211 | { 212 | struct ksmbd_dcerpc *dce = pipe->dce; 213 | int ret; 214 | 215 | switch (dce->req_hdr.opnum) { 216 | case WKSSVC_NETWKSTA_GET_INFO: 217 | dcerpc_set_ext_payload(dce, resp->payload, max_resp_sz); 218 | 219 | ret = wkssvc_netwksta_info_return(pipe); 220 | break; 221 | default: 222 | pr_err("WKSSVC: unsupported RETURN method %d\n", 223 | dce->req_hdr.opnum); 224 | ret = KSMBD_RPC_EBAD_FUNC; 225 | break; 226 | } 227 | return ret; 228 | } 229 | 230 | int rpc_wkssvc_read_request(struct ksmbd_rpc_pipe *pipe, 231 | struct ksmbd_rpc_command *resp, 232 | int max_resp_sz) 233 | { 234 | return wkssvc_return(pipe, resp, max_resp_sz); 235 | } 236 | 237 | int rpc_wkssvc_write_request(struct ksmbd_rpc_pipe *pipe) 238 | { 239 | return wkssvc_invoke(pipe); 240 | } 241 | -------------------------------------------------------------------------------- /tools/management/tree_conn.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * Copyright (C) 2018 Samsung Electronics Co., Ltd. 4 | * 5 | * linux-cifsd-devel@lists.sourceforge.net 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "linux/ksmbd_server.h" 13 | #include "management/tree_conn.h" 14 | #include "management/session.h" 15 | #include "management/share.h" 16 | #include "management/user.h" 17 | #include "tools.h" 18 | 19 | static struct ksmbd_tree_conn *new_ksmbd_tree_conn(void) 20 | { 21 | struct ksmbd_tree_conn *conn; 22 | 23 | conn = g_try_malloc0(sizeof(struct ksmbd_tree_conn)); 24 | if (!conn) 25 | return NULL; 26 | 27 | conn->id = 0; 28 | return conn; 29 | } 30 | 31 | void tcm_tree_conn_free(struct ksmbd_tree_conn *conn) 32 | { 33 | shm_close_connection(conn->share); 34 | put_ksmbd_share(conn->share); 35 | g_free(conn); 36 | } 37 | 38 | int tcm_handle_tree_connect(struct ksmbd_tree_connect_request *req, 39 | struct ksmbd_tree_connect_response *resp) 40 | { 41 | struct ksmbd_user *user = NULL; 42 | struct ksmbd_share *share = NULL; 43 | struct ksmbd_tree_conn *conn = new_ksmbd_tree_conn(); 44 | int ret; 45 | 46 | if (!conn) { 47 | resp->status = KSMBD_TREE_CONN_STATUS_NOMEM; 48 | return -ENOMEM; 49 | } 50 | 51 | if (sm_check_sessions_capacity(req->session_id)) { 52 | resp->status = KSMBD_TREE_CONN_STATUS_TOO_MANY_SESSIONS; 53 | pr_debug("treecon: Too many active sessions\n"); 54 | goto out_error; 55 | } 56 | 57 | if (global_conf.map_to_guest == KSMBD_CONF_MAP_TO_GUEST_NEVER) { 58 | if (req->account_flags & KSMBD_USER_FLAG_BAD_PASSWORD) { 59 | resp->status = KSMBD_TREE_CONN_STATUS_INVALID_USER; 60 | pr_debug("treecon: Bad user password\n"); 61 | goto out_error; 62 | } 63 | } 64 | 65 | share = shm_lookup_share(req->share); 66 | if (!share) { 67 | resp->status = KSMBD_TREE_CONN_STATUS_NO_SHARE; 68 | pr_err("treecon: Unknown net share: %s\n", req->share); 69 | goto out_error; 70 | } 71 | 72 | if (test_share_flag(share, KSMBD_SHARE_FLAG_WRITEABLE)) 73 | set_conn_flag(conn, KSMBD_TREE_CONN_FLAG_WRITABLE); 74 | if (test_share_flag(share, KSMBD_SHARE_FLAG_READONLY)) 75 | set_conn_flag(conn, KSMBD_TREE_CONN_FLAG_READ_ONLY); 76 | if (test_share_flag(share, KSMBD_SHARE_FLAG_UPDATE)) 77 | set_conn_flag(conn, KSMBD_TREE_CONN_FLAG_UPDATE); 78 | 79 | if (shm_open_connection(share)) { 80 | resp->status = KSMBD_TREE_CONN_STATUS_TOO_MANY_CONNS; 81 | pr_debug("treecon: Too many connections to net share\n"); 82 | goto out_error; 83 | } 84 | 85 | ret = shm_lookup_hosts_map(share, 86 | KSMBD_SHARE_HOSTS_ALLOW_MAP, 87 | req->peer_addr); 88 | if (ret == -ENOENT) { 89 | resp->status = KSMBD_TREE_CONN_STATUS_HOST_DENIED; 90 | pr_debug("treecon: Host denied: %s\n", req->peer_addr); 91 | goto out_error; 92 | } 93 | 94 | if (ret != 0) { 95 | ret = shm_lookup_hosts_map(share, 96 | KSMBD_SHARE_HOSTS_DENY_MAP, 97 | req->peer_addr); 98 | if (ret == 0) { 99 | resp->status = KSMBD_TREE_CONN_STATUS_HOST_DENIED; 100 | pr_err("treecon: Host denied: %s\n", req->peer_addr); 101 | goto out_error; 102 | } 103 | } 104 | 105 | if (global_conf.restrict_anon >= KSMBD_RESTRICT_ANON_TYPE_1) { 106 | int deny; 107 | 108 | deny = !test_share_flag(share, KSMBD_SHARE_FLAG_GUEST_OK); 109 | deny |= test_share_flag(share, KSMBD_SHARE_FLAG_PIPE); 110 | 111 | if (req->account_flags & KSMBD_USER_FLAG_GUEST_ACCOUNT && 112 | deny) { 113 | pr_debug("treecon: Deny, restricted session\n"); 114 | resp->status = KSMBD_TREE_CONN_STATUS_ERROR; 115 | goto out_error; 116 | } 117 | } 118 | 119 | if ((req->account_flags & KSMBD_USER_FLAG_GUEST_ACCOUNT) && 120 | !test_share_flag(share, KSMBD_SHARE_FLAG_GUEST_OK)) { 121 | pr_debug("treecon: Deny, guest not allowed\n"); 122 | resp->status = KSMBD_TREE_CONN_STATUS_ERROR; 123 | goto out_error; 124 | } 125 | 126 | if ((req->account_flags & KSMBD_USER_FLAG_GUEST_ACCOUNT) && 127 | test_share_flag(share, KSMBD_SHARE_FLAG_GUEST_OK)) { 128 | pr_debug("treecon: Net share permits guest login\n"); 129 | user = usm_lookup_user(share->guest_account); 130 | if (user) { 131 | set_conn_flag(conn, KSMBD_TREE_CONN_FLAG_GUEST_ACCOUNT); 132 | goto bind; 133 | } 134 | 135 | user = usm_lookup_user(global_conf.guest_account); 136 | if (user) { 137 | set_conn_flag(conn, KSMBD_TREE_CONN_FLAG_GUEST_ACCOUNT); 138 | goto bind; 139 | } 140 | } 141 | 142 | user = usm_lookup_user(req->account); 143 | if (!user) { 144 | resp->status = KSMBD_TREE_CONN_STATUS_NO_USER; 145 | pr_err("treecon: User `%s' not found\n", req->account); 146 | goto out_error; 147 | } 148 | 149 | user->failed_login_count = 0; 150 | user->flags &= ~KSMBD_USER_FLAG_DELAY_SESSION; 151 | 152 | if (test_user_flag(user, KSMBD_USER_FLAG_GUEST_ACCOUNT)) 153 | set_conn_flag(conn, KSMBD_TREE_CONN_FLAG_GUEST_ACCOUNT); 154 | 155 | ret = shm_lookup_users_map(share, 156 | KSMBD_SHARE_ADMIN_USERS_MAP, 157 | req->account); 158 | if (ret == 0) { 159 | set_conn_flag(conn, KSMBD_TREE_CONN_FLAG_ADMIN_ACCOUNT); 160 | goto bind; 161 | } 162 | 163 | ret = shm_lookup_users_map(share, 164 | KSMBD_SHARE_INVALID_USERS_MAP, 165 | req->account); 166 | if (ret == 0) { 167 | resp->status = KSMBD_TREE_CONN_STATUS_INVALID_USER; 168 | pr_err("treecon: User is on invalid users list\n"); 169 | goto out_error; 170 | } 171 | 172 | ret = shm_lookup_users_map(share, 173 | KSMBD_SHARE_READ_LIST_MAP, 174 | req->account); 175 | if (ret == 0) { 176 | set_conn_flag(conn, KSMBD_TREE_CONN_FLAG_READ_ONLY); 177 | clear_conn_flag(conn, KSMBD_TREE_CONN_FLAG_WRITABLE); 178 | goto bind; 179 | } 180 | 181 | ret = shm_lookup_users_map(share, 182 | KSMBD_SHARE_WRITE_LIST_MAP, 183 | req->account); 184 | if (ret == 0) { 185 | set_conn_flag(conn, KSMBD_TREE_CONN_FLAG_WRITABLE); 186 | goto bind; 187 | } 188 | 189 | ret = shm_lookup_users_map(share, 190 | KSMBD_SHARE_VALID_USERS_MAP, 191 | req->account); 192 | if (ret == 0) 193 | goto bind; 194 | if (ret == -ENOENT) { 195 | resp->status = KSMBD_TREE_CONN_STATUS_INVALID_USER; 196 | pr_err("treecon: User is not on valid users list\n"); 197 | goto out_error; 198 | } 199 | 200 | bind: 201 | conn->id = req->connect_id; 202 | conn->share = share; 203 | resp->status = KSMBD_TREE_CONN_STATUS_OK; 204 | resp->connection_flags = conn->flags; 205 | 206 | if (sm_handle_tree_connect(req->session_id, user, conn)) 207 | pr_err("treecon: Unable to bind tree connection\n"); 208 | 209 | g_rw_lock_writer_lock(&share->update_lock); 210 | clear_share_flag(share, KSMBD_SHARE_FLAG_UPDATE); 211 | g_rw_lock_writer_unlock(&share->update_lock); 212 | 213 | return 0; 214 | out_error: 215 | tcm_tree_conn_free(conn); 216 | shm_close_connection(share); 217 | put_ksmbd_share(share); 218 | put_ksmbd_user(user); 219 | return -EINVAL; 220 | } 221 | 222 | int tcm_handle_tree_disconnect(unsigned long long sess_id, 223 | unsigned long long tree_conn_id) 224 | { 225 | sm_handle_tree_disconnect(sess_id, tree_conn_id); 226 | return 0; 227 | } 228 | -------------------------------------------------------------------------------- /include/tools.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /* 3 | * Copyright (C) 2018 Samsung Electronics Co., Ltd. 4 | * 5 | * linux-cifsd-devel@lists.sourceforge.net 6 | */ 7 | 8 | #ifndef __TOOLS_H__ 9 | #define __TOOLS_H__ 10 | 11 | #ifndef _GNU_SOURCE 12 | #define _GNU_SOURCE 1 13 | #endif 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #ifdef HAVE_CONFIG_H 29 | #include 30 | #endif 31 | 32 | struct smbconf_global { 33 | int flags; 34 | int map_to_guest; 35 | char *guest_account; 36 | 37 | char *server_string; 38 | char *work_group; 39 | char *netbios_name; 40 | char *server_min_protocol; 41 | char *server_max_protocol; 42 | char *root_dir; 43 | int server_signing; 44 | int sessions_cap; 45 | int restrict_anon; 46 | unsigned short tcp_port; 47 | unsigned short ipc_timeout; 48 | unsigned int deadtime; 49 | bool bind_interfaces_only; 50 | char **interfaces; 51 | unsigned long file_max; 52 | unsigned int smb2_max_read; 53 | unsigned int smb2_max_write; 54 | unsigned int smb2_max_trans; 55 | unsigned int smb2_max_credits; 56 | unsigned int smbd_max_io_size; 57 | unsigned int max_connections; 58 | unsigned int max_ip_connections; 59 | unsigned int share_fake_fscaps; 60 | unsigned int gen_subauth[3]; 61 | char *krb5_keytab_file; 62 | char *krb5_service_name; 63 | int krb5_support; 64 | char *pwddb; 65 | char *smbconf; 66 | pid_t pid; 67 | }; 68 | 69 | #define KSMBD_RESTRICT_ANON_TYPE_1 1 70 | #define KSMBD_RESTRICT_ANON_TYPE_2 2 71 | 72 | extern struct smbconf_global global_conf; 73 | 74 | #define KSMBD_CONF_MAP_TO_GUEST_NEVER (0) 75 | #define KSMBD_CONF_MAP_TO_GUEST_BAD_USER (1 << 0) 76 | #define KSMBD_CONF_MAP_TO_GUEST_BAD_PASSWORD (1 << 1) 77 | #define KSMBD_CONF_MAP_TO_GUEST_BAD_UID (1 << 2) 78 | 79 | #define KSMBD_CONF_MAX_OPEN_FILES 65536 /* TODO */ 80 | #define KSMBD_CONF_MAX_ACTIVE_SESSIONS 65536 /* TODO */ 81 | #define KSMBD_CONF_MAX_CONNECTIONS 65536 82 | 83 | #define PATH_PWDDB SYSCONFDIR "/ksmbd/ksmbdpwd.db" 84 | #define PATH_SMBCONF SYSCONFDIR "/ksmbd/ksmbd.conf" 85 | #define PATH_SUBAUTH SYSCONFDIR "/ksmbd/ksmbd.subauth" 86 | #define PATH_LOCK RUNSTATEDIR "/ksmbd.lock" 87 | #define PATH_FIFO RUNSTATEDIR "/ksmbd.fifo" 88 | 89 | #define KSMBD_HEALTH_START (0) 90 | #define KSMBD_HEALTH_RUNNING (1 << 0) 91 | #define KSMBD_SHOULD_RELOAD_CONFIG (1 << 1) 92 | #define KSMBD_SHOULD_LIST_CONFIG (1 << 2) 93 | 94 | extern int ksmbd_health_status; 95 | 96 | #define TRACING_DUMP_NL_MSG 0 97 | 98 | #define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0])) 99 | 100 | #define STR_HELPER(x) #x 101 | #define STR(x) STR_HELPER(x) 102 | 103 | //---------------------------------------------------------------// 104 | #define LOGAPP "[%s/%d]:" 105 | #define PRERR LOGAPP" ERROR: " 106 | #define PRINF LOGAPP" INFO: " 107 | #define PRDEBUG LOGAPP" DEBUG: " 108 | 109 | #define PR_ERROR 0 110 | #define PR_INFO 1 111 | #define PR_DEBUG 2 112 | 113 | extern int log_level; 114 | 115 | #define PR_LOGGER_STDIO 0 116 | #define PR_LOGGER_SYSLOG 1 117 | 118 | G_GNUC_PRINTF(2, 3) 119 | extern void __pr_log(int level, const char *fmt, ...); 120 | extern void pr_logger_init(int flags); 121 | extern int set_log_level(int level); 122 | 123 | #define pr_log(l, f, ...) \ 124 | do { \ 125 | if ((l) <= log_level) \ 126 | __pr_log((l), \ 127 | (f), \ 128 | get_tool_name(), \ 129 | getpid(), \ 130 | ##__VA_ARGS__); \ 131 | } while (0) 132 | 133 | #define pr_debug(f, ...) \ 134 | pr_log(PR_DEBUG, PRDEBUG f, ##__VA_ARGS__) 135 | #define pr_info(f, ...) \ 136 | pr_log(PR_INFO, PRINF f, ##__VA_ARGS__) 137 | #define pr_err(f, ...) \ 138 | pr_log(PR_ERROR, PRERR f, ##__VA_ARGS__) 139 | 140 | //---------------------------------------------------------------// 141 | 142 | void pr_hex_dump(const void *mem, size_t sz); 143 | 144 | char *base64_encode(unsigned char *src, size_t srclen); 145 | unsigned char *base64_decode(char const *src, size_t *dstlen); 146 | 147 | gchar *ksmbd_gconvert(const gchar *str, 148 | gssize str_len, 149 | int to_codeset, 150 | int from_codeset, 151 | gsize *bytes_read, 152 | gsize *bytes_written); 153 | 154 | enum charset_idx { 155 | KSMBD_CHARSET_UTF8 = 0, 156 | KSMBD_CHARSET_UTF16LE, 157 | KSMBD_CHARSET_UCS2LE, 158 | KSMBD_CHARSET_UTF16BE, 159 | KSMBD_CHARSET_UCS2BE, 160 | KSMBD_CHARSET_MAX = 5, 161 | }; 162 | 163 | #define KSMBD_CHARSET_DEFAULT KSMBD_CHARSET_UTF8 164 | 165 | extern char *ksmbd_conv_charsets[KSMBD_CHARSET_MAX + 1]; 166 | 167 | char **gptrarray_to_strv(GPtrArray *gptrarray); 168 | char *gptrarray_to_str(GPtrArray *gptrarray); 169 | void gptrarray_printf(GPtrArray *gptrarray, const char *fmt, ...); 170 | int set_conf_contents(const char *conf, const char *contents); 171 | 172 | int load_config(char *pwddb, char *smbconf); 173 | void remove_config(void); 174 | 175 | extern int set_tool_main(char *name); 176 | extern const char *get_tool_name(void); 177 | 178 | int show_version(void); 179 | 180 | typedef int tool_main_fn(int argc, char **argv); 181 | tool_main_fn addshare_main, adduser_main, control_main, mountd_main; 182 | extern tool_main_fn *tool_main; 183 | 184 | #define TOOL_IS_ADDSHARE \ 185 | (tool_main == addshare_main) 186 | #define TOOL_IS_ADDUSER \ 187 | (tool_main == adduser_main) 188 | #define TOOL_IS_CONTROL \ 189 | (tool_main == control_main) 190 | #define TOOL_IS_MOUNTD \ 191 | (tool_main == mountd_main) 192 | 193 | #define SELECT_NAME(_1, _2, _3, _4, NAME, ...) NAME 194 | 195 | #define ghash_for_each_3(v, tbl, iter) \ 196 | for (g_hash_table_iter_init(&iter, tbl); \ 197 | g_hash_table_iter_next(&iter, NULL, (gpointer *)&v); \ 198 | ) 199 | 200 | #define ghash_for_each_4(k, v, tbl, iter) \ 201 | for (g_hash_table_iter_init(&iter, tbl); \ 202 | g_hash_table_iter_next(&iter, (gpointer *)&k, (gpointer *)&v); \ 203 | ) 204 | 205 | #define ghash_for_each(...) \ 206 | SELECT_NAME(__VA_ARGS__, \ 207 | ghash_for_each_4, \ 208 | ghash_for_each_3)(__VA_ARGS__) 209 | 210 | #define ghash_for_each_remove_3(v, tbl, iter) \ 211 | for (g_hash_table_iter_init(&iter, tbl); \ 212 | g_hash_table_iter_next(&iter, NULL, (gpointer *)&v); \ 213 | g_hash_table_iter_remove(&iter)) 214 | 215 | #define ghash_for_each_remove_4(k, v, tbl, iter) \ 216 | for (g_hash_table_iter_init(&iter, tbl); \ 217 | g_hash_table_iter_next(&iter, (gpointer *)&k, (gpointer *)&v); \ 218 | g_hash_table_iter_remove(&iter)) 219 | 220 | #define ghash_for_each_remove(...) \ 221 | SELECT_NAME(__VA_ARGS__, \ 222 | ghash_for_each_remove_4, \ 223 | ghash_for_each_remove_3)(__VA_ARGS__) 224 | 225 | #define ghash_for_each_steal_3(v, tbl, iter) \ 226 | for (g_hash_table_iter_init(&iter, tbl); \ 227 | g_hash_table_iter_next(&iter, NULL, (gpointer *)&v); \ 228 | g_hash_table_iter_steal(&iter)) 229 | 230 | #define ghash_for_each_steal_4(k, v, tbl, iter) \ 231 | for (g_hash_table_iter_init(&iter, tbl); \ 232 | g_hash_table_iter_next(&iter, (gpointer *)&k, (gpointer *)&v); \ 233 | g_hash_table_iter_steal(&iter)) 234 | 235 | #define ghash_for_each_steal(...) \ 236 | SELECT_NAME(__VA_ARGS__, \ 237 | ghash_for_each_steal_4, \ 238 | ghash_for_each_steal_3)(__VA_ARGS__) 239 | 240 | #endif /* __TOOLS_H__ */ 241 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ksmbd-tools 2 | 3 | [![Build Status](https://app.travis-ci.com/cifsd-team/ksmbd-tools.svg?branch=master)](https://app.travis-ci.com/cifsd-team/ksmbd-tools) 4 | [![License](https://img.shields.io/badge/License-GPL_v2-blue.svg)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) 5 | 6 | [ksmbd-tools](https://github.com/cifsd-team/ksmbd-tools) 7 | is a collection of userspace utilities for 8 | [the ksmbd kernel server](https://www.kernel.org/doc/html/latest/filesystems/smb/ksmbd.html) 9 | merged to mainline in the Linux 5.15 release. 10 | 11 | ## Table of Contents 12 | 13 | - [Building and Installing](#building-and-installing) 14 | - [Usage](#usage) 15 | - [Packages](#packages) 16 | 17 | ## Building and Installing 18 | 19 | You should first check if your distribution has a package for ksmbd-tools, 20 | and if that is the case, consider installing it from the package manager. 21 | Otherwise, follow these instructions to build it yourself. Either the GNU 22 | Autotools or Meson build system can be used. 23 | 24 | Dependencies for Debian and its derivatives: `git` `gcc` `pkgconf` `autoconf` 25 | `automake` `libtool` `make` `meson` `ninja-build` `gawk` `libnl-3-dev` 26 | `libnl-genl-3-dev` `libglib2.0-dev` 27 | 28 | Dependencies for RHEL and its derivatives: `git` `gcc` `pkgconf` `autoconf` 29 | `automake` `libtool` `make` `meson` `ninja-build` `gawk` `libnl3-devel` 30 | `glib2-devel` 31 | 32 | Example build and install: 33 | ```sh 34 | git clone https://github.com/cifsd-team/ksmbd-tools.git 35 | cd ksmbd-tools 36 | 37 | # autotools build 38 | 39 | ./autogen.sh 40 | ./configure --with-rundir=/run 41 | 42 | make 43 | sudo make install 44 | 45 | # meson build 46 | 47 | mkdir build 48 | cd build 49 | meson -Drundir=/run .. 50 | 51 | ninja 52 | sudo ninja install 53 | ``` 54 | 55 | By default, the utilities are in `/usr/local/sbin` and the files they use by 56 | default are under `/usr/local/etc` in the `ksmbd` directory. 57 | 58 | If you would like to install ksmbd-tools under `/usr`, where it may conflict 59 | with ksmbd-tools installed using the package manager, give `--prefix=/usr` 60 | and `--sysconfdir=/etc` as options to `configure` or `meson`. In that case, 61 | the utilities are in `/usr/sbin` and the files they use by default are under 62 | `/etc` in the `ksmbd` directory. 63 | 64 | It is likely that you should give `--with-rundir` or `-Drundir` as an option 65 | to `configure` or `meson`, respectively. This is due to it being likely that 66 | your system does not mount a tmpfs filesystem at the directory given by the 67 | default value. Common choices are `/run`, `/var/run`, or `/tmp`. ksmbd-tools 68 | uses the directory for per-process modifiable data, namely the `ksmbd.lock` 69 | file holding the PID of the `ksmbd.mountd` manager process. If your autoconf 70 | supports it, you may instead choose to give `--runstatedir` to `configure`. 71 | 72 | If you have systemd and it meets at least the minimum version required, the 73 | build will install the `ksmbd.service` unit file. The unit file supports the 74 | usual unit commands and handles loading of the kernel module. Note that the 75 | location of the unit file may conflict with ksmbd-tools installed using the 76 | package manager. You can bypass the version check and choose the unit file 77 | directory yourself by giving `--with-systemdsystemunitdir=DIR` or 78 | `-Dsystemdsystemunitdir=DIR` as an option to either `configure` or `meson`, 79 | respectively. 80 | 81 | ## Usage 82 | 83 | Manual pages: 84 | ```sh 85 | man 8 ksmbd.addshare 86 | man 8 ksmbd.adduser 87 | man 8 ksmbd.control 88 | man 8 ksmbd.mountd 89 | man 5 ksmbd.conf 90 | man 5 ksmbdpwd.db 91 | ``` 92 | 93 | Example session: 94 | ```sh 95 | # If you built and installed ksmbd-tools yourself using autoconf defaults, 96 | # the utilities are in `/usr/local/sbin', 97 | # the default user database is `/usr/local/etc/ksmbd/ksmbdpwd.db', and 98 | # the default configuration file is `/usr/local/etc/ksmbd/ksmbd.conf'. 99 | 100 | # Otherwise it is likely that, 101 | # the utilities are in `/usr/sbin', 102 | # the default user database is `/etc/ksmbd/ksmbdpwd.db', and 103 | # the default configuration file is `/etc/ksmbd/ksmbd.conf'. 104 | 105 | # Create the share path directory. 106 | # The share stores files in this directory using its underlying filesystem. 107 | mkdir -vp $HOME/MyShare 108 | 109 | # Add a share to the default configuration file. 110 | # Note that `ksmbd.addshare' does not do variable expansion. 111 | # Without `--add', `ksmbd.addshare' will update `MyShare' if it exists. 112 | sudo ksmbd.addshare --add \ 113 | --option "path = $HOME/MyShare" \ 114 | --option 'read only = no' \ 115 | MyShare 116 | 117 | # The default configuration file now has a new section for `MyShare'. 118 | # 119 | # [MyShare] 120 | # ; share parameters 121 | # path = /home/tester/MyShare 122 | # read only = no 123 | # 124 | # Each share has its own section with share parameters that apply to it. 125 | # A share parameter given in `[global]' changes its default value. 126 | # `[global]' also has global parameters which are not share specific. 127 | 128 | # You can interactively update a share by omitting `--option'. 129 | # Without `--update', `ksmbd.addshare' will add `MyShare' if it does not exist. 130 | sudo ksmbd.addshare --update MyShare 131 | 132 | # Add a user to the default user database. 133 | # You will be prompted for a password. 134 | sudo ksmbd.adduser --add MyUser 135 | 136 | # There is no system user called `MyUser' so it has to be mapped to one. 137 | # We can force all users accessing the share to map to a system user and group. 138 | 139 | # Update share parameters of a share in the default configuration file. 140 | sudo ksmbd.addshare --update \ 141 | --option "force user = $USER" \ 142 | --option "force group = $USER" \ 143 | MyShare 144 | 145 | # The default configuration file now has the updated share parameters. 146 | # 147 | # [MyShare] 148 | # ; share parameters 149 | # force group = tester 150 | # force user = tester 151 | # path = /home/tester/MyShare 152 | # read only = no 153 | # 154 | 155 | # Add the kernel module. 156 | sudo modprobe ksmbd 157 | 158 | # Start the user and kernel mode daemons. 159 | # All interfaces are listened to by default. 160 | sudo ksmbd.mountd 161 | 162 | # Mount the new share with cifs-utils and authenticate as the new user. 163 | # You will be prompted for the password given previously with `ksmbd.adduser'. 164 | sudo mount -o user=MyUser //127.0.0.1/MyShare /mnt 165 | 166 | # You can now access the share at `/mnt'. 167 | sudo touch /mnt/new_file_from_cifs_utils 168 | 169 | # Unmount the share. 170 | sudo umount /mnt 171 | 172 | # Update the password of a user in the default user database. 173 | # `--password' can be used to give the password instead of prompting. 174 | sudo ksmbd.adduser --update --password MyNewPassword MyUser 175 | 176 | # Delete a user from the default user database. 177 | sudo ksmbd.adduser --delete MyUser 178 | 179 | # The utilities notify ksmbd.mountd of changes by sending it the SIGHUP signal. 180 | # This can be done manually when changes are made without using the utilities. 181 | sudo ksmbd.control --reload 182 | 183 | # Toggle ksmbd debug printing of the `smb' component. 184 | sudo ksmbd.control --debug smb 185 | 186 | # Some changes require restarting the user and kernel mode daemons. 187 | # Modifying any global parameter is one example of such a change. 188 | # Restarting means starting `ksmbd.mountd' after shutting the daemons down. 189 | 190 | # Shutdown the user and kernel mode daemons. 191 | sudo ksmbd.control --shutdown 192 | 193 | # Remove the kernel module. 194 | sudo modprobe -r ksmbd 195 | ``` 196 | 197 | ## Packages 198 | 199 | The following packaging status tracker is provided by 200 | [the Repology project](https://repology.org) 201 | . 202 | 203 | [![Packaging status](https://repology.org/badge/vertical-allrepos/ksmbd-tools.svg)](https://repology.org/project/ksmbd-tools/versions) 204 | -------------------------------------------------------------------------------- /tools/tools.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * Copyright (C) 2018 Samsung Electronics Co., Ltd. 4 | * 5 | * linux-cifsd-devel@lists.sourceforge.net 6 | */ 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include "tools.h" 16 | #include "ipc.h" 17 | #include "rpc.h" 18 | #include "worker.h" 19 | #include "config_parser.h" 20 | #include "management/user.h" 21 | #include "management/share.h" 22 | #include "management/session.h" 23 | #include "management/tree_conn.h" 24 | #include "management/spnego.h" 25 | #include "version.h" 26 | 27 | int log_level = PR_INFO; 28 | int ksmbd_health_status; 29 | tool_main_fn *tool_main; 30 | 31 | static int log_open; 32 | 33 | typedef void (*logger)(int level, const char *fmt, va_list list); 34 | 35 | char *ksmbd_conv_charsets[KSMBD_CHARSET_MAX + 1] = { 36 | "UTF-8", 37 | "UTF-16LE", 38 | "UCS-2LE", 39 | "UTF-16BE", 40 | "UCS-2BE", 41 | "OOPS" 42 | }; 43 | 44 | static int syslog_level(int level) 45 | { 46 | if (level == PR_ERROR) 47 | return LOG_ERR; 48 | if (level == PR_INFO) 49 | return LOG_INFO; 50 | if (level == PR_DEBUG) 51 | return LOG_DEBUG; 52 | 53 | return LOG_ERR; 54 | } 55 | 56 | G_GNUC_PRINTF(2, 0) 57 | static void __pr_log_stdio(int level, const char *fmt, va_list list) 58 | { 59 | char buf[1024]; 60 | 61 | vsnprintf(buf, sizeof(buf), fmt, list); 62 | printf("%s", buf); 63 | } 64 | 65 | G_GNUC_PRINTF(2, 0) 66 | static void __pr_log_syslog(int level, const char *fmt, va_list list) 67 | { 68 | vsyslog(syslog_level(level), fmt, list); 69 | } 70 | 71 | static logger __logger = __pr_log_stdio; 72 | 73 | void __pr_log(int level, const char *fmt, ...) 74 | { 75 | va_list list; 76 | 77 | va_start(list, fmt); 78 | __logger(level, fmt, list); 79 | va_end(list); 80 | } 81 | 82 | void pr_logger_init(int flag) 83 | { 84 | if (flag == PR_LOGGER_SYSLOG) { 85 | if (log_open) { 86 | closelog(); 87 | log_open = 0; 88 | } 89 | openlog("ksmbd", LOG_NDELAY, LOG_LOCAL5); 90 | __logger = __pr_log_syslog; 91 | log_open = 1; 92 | } 93 | } 94 | 95 | int set_log_level(int level) 96 | { 97 | int old_level; 98 | 99 | if (log_level == PR_DEBUG) 100 | return log_level; 101 | 102 | old_level = log_level; 103 | log_level = level; 104 | return old_level; 105 | } 106 | 107 | #if TRACING_DUMP_NL_MSG 108 | #define PR_HEX_DUMP_WIDTH 160 109 | void pr_hex_dump(const void *mem, size_t sz) 110 | { 111 | char xline[PR_HEX_DUMP_WIDTH]; 112 | char sline[PR_HEX_DUMP_WIDTH]; 113 | int xi = 0, si = 0, mi = 0; 114 | 115 | while (mi < sz) { 116 | char c = *((char *)mem + mi); 117 | 118 | mi++; 119 | xi += sprintf(xline + xi, "%02X ", 0xff & c); 120 | if (c > ' ' && c < '~') 121 | si += sprintf(sline + si, "%c", c); 122 | else 123 | si += sprintf(sline + si, "."); 124 | if (xi >= PR_HEX_DUMP_WIDTH / 2) { 125 | pr_err("%s %s\n", xline, sline); 126 | xi = 0; 127 | si = 0; 128 | } 129 | } 130 | 131 | if (xi) { 132 | int sz = PR_HEX_DUMP_WIDTH / 2 - xi + 1; 133 | 134 | if (sz > 0) { 135 | memset(xline + xi, ' ', sz); 136 | xline[PR_HEX_DUMP_WIDTH / 2 + 1] = 0x00; 137 | } 138 | pr_err("%s %s\n", xline, sline); 139 | } 140 | } 141 | #else 142 | void pr_hex_dump(const void *mem, size_t sz) 143 | { 144 | } 145 | #endif 146 | 147 | char *base64_encode(unsigned char *src, size_t srclen) 148 | { 149 | return g_base64_encode(src, srclen); 150 | } 151 | 152 | unsigned char *base64_decode(char const *src, size_t *dstlen) 153 | { 154 | unsigned char *ret = g_base64_decode(src, dstlen); 155 | 156 | if (ret) 157 | ret[*dstlen] = 0x00; 158 | return ret; 159 | } 160 | 161 | static int codeset_has_altname(int codeset) 162 | { 163 | if (codeset == KSMBD_CHARSET_UTF16LE || 164 | codeset == KSMBD_CHARSET_UTF16BE) 165 | return 1; 166 | return 0; 167 | } 168 | 169 | gchar *ksmbd_gconvert(const gchar *str, 170 | gssize str_len, 171 | int to_codeset, 172 | int from_codeset, 173 | gsize *bytes_read, 174 | gsize *bytes_written) 175 | { 176 | gchar *converted; 177 | GError *err; 178 | 179 | retry: 180 | err = NULL; 181 | if (from_codeset >= KSMBD_CHARSET_MAX) { 182 | pr_err("Unknown source codeset: %d\n", from_codeset); 183 | return NULL; 184 | } 185 | 186 | if (to_codeset >= KSMBD_CHARSET_MAX) { 187 | pr_err("Unknown target codeset: %d\n", to_codeset); 188 | return NULL; 189 | } 190 | 191 | converted = g_convert(str, 192 | str_len, 193 | ksmbd_conv_charsets[to_codeset], 194 | ksmbd_conv_charsets[from_codeset], 195 | bytes_read, 196 | bytes_written, 197 | &err); 198 | if (err) { 199 | int has_altname = 0; 200 | 201 | if (codeset_has_altname(to_codeset)) { 202 | to_codeset++; 203 | has_altname = 1; 204 | } 205 | 206 | if (codeset_has_altname(from_codeset)) { 207 | from_codeset++; 208 | has_altname = 1; 209 | } 210 | 211 | pr_info("%s\n", err->message); 212 | g_error_free(err); 213 | 214 | if (has_altname) { 215 | pr_info("Will try `%s' and `%s'\n", 216 | ksmbd_conv_charsets[to_codeset], 217 | ksmbd_conv_charsets[from_codeset]); 218 | goto retry; 219 | } 220 | 221 | return NULL; 222 | } 223 | 224 | return converted; 225 | } 226 | 227 | char **gptrarray_to_strv(GPtrArray *gptrarray) 228 | { 229 | if (!gptrarray->len || 230 | g_ptr_array_index(gptrarray, gptrarray->len - 1)) 231 | g_ptr_array_add(gptrarray, NULL); 232 | 233 | return (char **)g_ptr_array_free(gptrarray, 0); 234 | } 235 | 236 | static char *strv_to_str(char **strv) 237 | { 238 | char *str = g_strjoinv(NULL, strv); 239 | 240 | g_strfreev(strv); 241 | return str; 242 | } 243 | 244 | char *gptrarray_to_str(GPtrArray *gptrarray) 245 | { 246 | return strv_to_str(gptrarray_to_strv(gptrarray)); 247 | } 248 | 249 | void gptrarray_printf(GPtrArray *gptrarray, const char *fmt, ...) 250 | { 251 | va_list args; 252 | 253 | va_start(args, fmt); 254 | g_ptr_array_add(gptrarray, g_strdup_vprintf(fmt, args)); 255 | va_end(args); 256 | } 257 | 258 | int set_conf_contents(const char *conf, const char *contents) 259 | { 260 | GError *error = NULL; 261 | mode_t mask = umask(~(S_IRUSR | S_IWUSR | S_IRGRP)); 262 | 263 | g_file_set_contents(conf, contents, -1, &error); 264 | umask(mask); 265 | if (error) { 266 | pr_err("%s\n", error->message); 267 | g_error_free(error); 268 | return -EINVAL; 269 | } 270 | pr_info("Wrote `%s'\n", conf); 271 | return 0; 272 | } 273 | 274 | int load_config(char *pwddb, char *smbconf) 275 | { 276 | int ret; 277 | 278 | usm_init(); 279 | 280 | if (TOOL_IS_MOUNTD) 281 | usm_remove_all_users(); 282 | 283 | ret = cp_parse_pwddb(pwddb); 284 | if (ret) 285 | return ret; 286 | 287 | if (TOOL_IS_ADDSHARE) 288 | cp_smbconf_parser_init(); 289 | 290 | shm_init(); 291 | 292 | if (TOOL_IS_MOUNTD) 293 | shm_remove_all_shares(); 294 | 295 | ret = cp_parse_smbconf(smbconf); 296 | if (ret) 297 | return ret; 298 | 299 | if (TOOL_IS_MOUNTD) { 300 | sm_init(); 301 | rpc_init(); 302 | ipc_init(); 303 | spnego_init(); 304 | wp_init(); 305 | } 306 | 307 | return ret; 308 | } 309 | 310 | void remove_config(void) 311 | { 312 | if (TOOL_IS_MOUNTD) { 313 | wp_destroy(); 314 | spnego_destroy(); 315 | ipc_destroy(); 316 | rpc_destroy(); 317 | sm_destroy(); 318 | } else if (TOOL_IS_ADDSHARE) { 319 | cp_smbconf_parser_destroy(); 320 | } 321 | 322 | shm_destroy(); 323 | usm_destroy(); 324 | } 325 | 326 | int set_tool_main(char *name) 327 | { 328 | if (!strcmp(name, "ksmbd.addshare")) 329 | tool_main = addshare_main; 330 | else if (!strcmp(name, "ksmbd.adduser")) 331 | tool_main = adduser_main; 332 | else if (!strcmp(name, "ksmbd.control")) 333 | tool_main = control_main; 334 | else if (!strcmp(name, "ksmbd.mountd")) 335 | tool_main = mountd_main; 336 | else 337 | tool_main = NULL; 338 | 339 | return !tool_main ? -EINVAL : 0; 340 | } 341 | 342 | const char *get_tool_name(void) 343 | { 344 | if (TOOL_IS_ADDSHARE) 345 | return "ksmbd.addshare"; 346 | if (TOOL_IS_ADDUSER) 347 | return "ksmbd.adduser"; 348 | if (TOOL_IS_CONTROL) 349 | return "ksmbd.control"; 350 | if (TOOL_IS_MOUNTD) { 351 | if (getppid() == global_conf.pid) 352 | return "ksmbd.mountd(worker)"; 353 | if (getpid() == global_conf.pid) 354 | return "ksmbd.mountd(manager)"; 355 | return "ksmbd.mountd"; 356 | } 357 | return "ksmbd.tools"; 358 | } 359 | 360 | int show_version(void) 361 | { 362 | pr_info("ksmbd-tools version : %s\n", KSMBD_TOOLS_VERSION); 363 | return 0; 364 | } 365 | 366 | int main(int argc, char **argv) 367 | { 368 | char *base_name; 369 | 370 | if (!*argv) 371 | return EXIT_FAILURE; 372 | 373 | base_name = strrchr(*argv, '/'); 374 | base_name = base_name ? base_name + 1 : *argv; 375 | if (set_tool_main(base_name)) { 376 | pr_err("Invalid base name `%s'\n", base_name); 377 | return EXIT_FAILURE; 378 | } 379 | 380 | return tool_main(argc, argv); 381 | } 382 | -------------------------------------------------------------------------------- /adduser/user_admin.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * Copyright (C) 2018 Samsung Electronics Co., Ltd. 4 | * 5 | * linux-cifsd-devel@lists.sourceforge.net 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | static void __prompt_password_stdin(char *password, size_t *sz) 28 | { 29 | struct termios term, raw_term; 30 | char buf[LINE_MAX]; 31 | size_t buflen; 32 | 33 | pr_info("Prompting for password\n"); 34 | 35 | tcgetattr(STDIN_FILENO, &term); 36 | raw_term = term; 37 | 38 | raw_term.c_lflag &= ~(ECHO | ICANON); 39 | tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw_term); 40 | 41 | for (*sz = (size_t)-1, 42 | buflen = 0, password[buflen] = buf[buflen] = 0x00;;) { 43 | int c; 44 | 45 | if (!buflen) { 46 | printf("\r" "\e[2K" "%s password: ", 47 | *password == 0x00 ? "New" : "Retype"); 48 | fflush(stdout); 49 | } 50 | 51 | c = getchar(); 52 | if (c == EOF || c == 0x04) 53 | break; 54 | 55 | if (c == '\n') { 56 | if (*password == 0x00 && buflen) { 57 | strncat(password, buf, MAX_NT_PWD_LEN - 1); 58 | buflen = 0; 59 | buf[buflen] = 0x00; 60 | printf("\eD"); 61 | continue; 62 | } 63 | if (strcmp(password, buf)) { 64 | *password = 0x00; 65 | buflen = 0; 66 | buf[buflen] = 0x00; 67 | printf("\r" "\e[2K" 68 | "\e[1m" "Passwords do not match!" "\e[m" 69 | "\eM"); 70 | continue; 71 | } 72 | if (!g_utf8_validate(password, -1, NULL)) { 73 | *password = 0x00; 74 | buflen = 0; 75 | buf[buflen] = 0x00; 76 | printf("\r" "\e[2K" 77 | "\e[1m" "Password is not UTF-8!" "\e[m" 78 | "\eM"); 79 | continue; 80 | } 81 | *sz = buflen + 1; 82 | break; 83 | } 84 | 85 | if (c == raw_term.c_cc[VERASE]) { 86 | char *u8c; 87 | size_t clen; 88 | 89 | u8c = g_utf8_find_prev_char(buf, buf + buflen); 90 | clen = u8c ? buf + buflen - u8c : 1; 91 | buflen -= buflen > clen ? clen : buflen; 92 | buf[buflen] = 0x00; 93 | continue; 94 | } 95 | 96 | if (buflen < LINE_MAX - 1) { 97 | buf[buflen++] = c; 98 | buf[buflen] = 0x00; 99 | if (!cp_printable(buf + buflen - 1)) 100 | buf[--buflen] = 0x00; 101 | } 102 | } 103 | 104 | printf("\eD" "\r" "\e[2K"); 105 | 106 | tcsetattr(STDIN_FILENO, TCSAFLUSH, &term); 107 | } 108 | 109 | static int __is_valid_password_len(size_t len) 110 | { 111 | int is_valid; 112 | 113 | is_valid = len < MAX_NT_PWD_LEN; 114 | if (!is_valid) { 115 | pr_err("Password exceeds %d bytes\n", 116 | MAX_NT_PWD_LEN - 1); 117 | goto out; 118 | } 119 | if (!len) 120 | pr_info("Password is empty\n"); 121 | out: 122 | return is_valid; 123 | } 124 | 125 | static void __utf16le_convert(char **password, size_t *sz) 126 | { 127 | size_t bytes_written; 128 | char *utf16le; 129 | 130 | utf16le = ksmbd_gconvert(*password, 131 | *sz - 1, 132 | KSMBD_CHARSET_UTF16LE, 133 | KSMBD_CHARSET_DEFAULT, 134 | NULL, 135 | &bytes_written); 136 | g_free(*password); 137 | 138 | *sz = !utf16le ? (size_t)-1 : bytes_written; 139 | *password = utf16le; 140 | } 141 | 142 | static void __md4_hash(char **password, size_t *sz) 143 | { 144 | struct md4_ctx mctx; 145 | 146 | md4_init(&mctx); 147 | md4_update(&mctx, *password, *sz); 148 | g_free(*password); 149 | 150 | *sz = sizeof(mctx.hash) + 1; 151 | *password = g_malloc0(*sz); 152 | md4_final(&mctx, *password); 153 | } 154 | 155 | static void __base64_encode(char **password, size_t *sz) 156 | { 157 | char *base64; 158 | 159 | base64 = base64_encode(*password, *sz - 1); 160 | g_free(*password); 161 | 162 | *sz = strlen(base64) + 1; 163 | *password = base64; 164 | } 165 | 166 | static int process_password(char **password) 167 | { 168 | size_t sz; 169 | 170 | if (!*password) { 171 | *password = g_malloc(MAX_NT_PWD_LEN); 172 | __prompt_password_stdin(*password, &sz); 173 | if (sz == (size_t)-1) 174 | return -EINVAL; 175 | } else { 176 | sz = strlen(*password) + 1; 177 | } 178 | 179 | if (!__is_valid_password_len(sz - 1)) 180 | return -EINVAL; 181 | 182 | __utf16le_convert(password, &sz); 183 | if (sz == (size_t)-1) 184 | return -EINVAL; 185 | 186 | __md4_hash(password, &sz); 187 | __base64_encode(password, &sz); 188 | return 0; 189 | } 190 | 191 | static void __new_user_nl_cb(struct ksmbd_user *user, GList **nl) 192 | { 193 | if (!test_user_flag(user, KSMBD_USER_FLAG_GUEST_ACCOUNT)) 194 | *nl = g_list_insert_sorted(*nl, 195 | user->name, 196 | (GCompareFunc)strcmp); 197 | } 198 | 199 | static GList *new_user_nl(void) 200 | { 201 | GList *nl = NULL; 202 | 203 | usm_iter_users((user_cb)__new_user_nl_cb, &nl); 204 | return nl; 205 | } 206 | 207 | static char *get_conf_contents(void) 208 | { 209 | GPtrArray *lines = g_ptr_array_new(); 210 | g_autoptr(GList) nl = new_user_nl(); 211 | GList *l; 212 | 213 | for (l = nl; l; l = l->next) { 214 | struct ksmbd_user *user = usm_lookup_user(l->data); 215 | 216 | gptrarray_printf(lines, "%s:%s\n", user->name, user->pass_b64); 217 | put_ksmbd_user(user); 218 | } 219 | return gptrarray_to_str(lines); 220 | } 221 | 222 | int command_add_user(char *pwddb, char *name, char *password) 223 | { 224 | g_autofree char *contents = NULL; 225 | struct ksmbd_user *user; 226 | int ret; 227 | 228 | user = usm_lookup_user(name); 229 | if (user) { 230 | put_ksmbd_user(user); 231 | pr_err("User `%s' already exists\n", name); 232 | ret = -EEXIST; 233 | goto out; 234 | } 235 | 236 | ret = process_password(&password); 237 | if (ret) 238 | goto out; 239 | 240 | ret = usm_add_new_user(g_strdup(name), g_strdup(password)); 241 | if (ret) { 242 | pr_err("Failed to add user `%s'\n", name); 243 | goto out; 244 | } 245 | 246 | contents = get_conf_contents(); 247 | ret = set_conf_contents(pwddb, contents); 248 | if (ret) 249 | goto out; 250 | 251 | pr_info("Added user `%s'\n", name); 252 | out: 253 | g_free(pwddb); 254 | g_free(name); 255 | g_free(password); 256 | return ret; 257 | } 258 | 259 | int command_update_user(char *pwddb, char *name, char *password) 260 | { 261 | g_autofree char *contents = NULL; 262 | struct ksmbd_user *user; 263 | int ret; 264 | 265 | user = usm_lookup_user(name); 266 | if (!user) { 267 | pr_err("User `%s' does not exist\n", name); 268 | ret = -EINVAL; 269 | goto out; 270 | } 271 | 272 | ret = process_password(&password); 273 | if (ret) 274 | goto out; 275 | 276 | usm_update_user_password(user, password); 277 | put_ksmbd_user(user); 278 | 279 | contents = get_conf_contents(); 280 | ret = set_conf_contents(pwddb, contents); 281 | if (ret) 282 | goto out; 283 | 284 | pr_info("Updated user `%s'\n", name); 285 | out: 286 | g_free(pwddb); 287 | g_free(name); 288 | g_free(password); 289 | return ret; 290 | } 291 | 292 | static void __share_transient_user_cb(struct ksmbd_share *share, 293 | char **user_name) 294 | { 295 | if (!*user_name) 296 | return; 297 | 298 | if (share->guest_account && !strcmp(*user_name, share->guest_account)) 299 | goto require; 300 | 301 | if (!shm_lookup_users_map(share, 302 | KSMBD_SHARE_ADMIN_USERS_MAP, 303 | *user_name)) 304 | goto require; 305 | 306 | if (!shm_lookup_users_map(share, 307 | KSMBD_SHARE_WRITE_LIST_MAP, 308 | *user_name)) 309 | goto require; 310 | 311 | if (!shm_lookup_users_map(share, 312 | KSMBD_SHARE_VALID_USERS_MAP, 313 | *user_name)) 314 | goto require; 315 | 316 | return; 317 | require: 318 | pr_err("Share `%s' requires user `%s'\n", share->name, *user_name); 319 | *user_name = NULL; 320 | } 321 | 322 | static int __is_transient_user(char *name) 323 | { 324 | int is_transient; 325 | 326 | is_transient = !global_conf.guest_account || 327 | strcmp(global_conf.guest_account, name); 328 | if (!is_transient) { 329 | pr_err("Server requires user `%s'\n", name); 330 | goto out; 331 | } 332 | shm_iter_shares((share_cb)__share_transient_user_cb, &name); 333 | is_transient = !!name; 334 | out: 335 | return is_transient; 336 | } 337 | 338 | int command_delete_user(char *pwddb, char *name, char *password) 339 | { 340 | g_autofree char *contents = NULL; 341 | struct ksmbd_user *user; 342 | int ret; 343 | 344 | user = usm_lookup_user(name); 345 | if (!user) { 346 | pr_err("User `%s' does not exist\n", name); 347 | ret = -EINVAL; 348 | goto out; 349 | } 350 | 351 | if (!__is_transient_user(name)) { 352 | ret = -EINVAL; 353 | goto out; 354 | } 355 | 356 | usm_remove_user(user); 357 | 358 | contents = get_conf_contents(); 359 | ret = set_conf_contents(pwddb, contents); 360 | if (ret) 361 | goto out; 362 | 363 | pr_info("Deleted user `%s'\n", name); 364 | out: 365 | g_free(pwddb); 366 | g_free(name); 367 | g_free(password); 368 | return ret; 369 | } 370 | -------------------------------------------------------------------------------- /control/control.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * Copyright (C) 2020 Samsung Electronics Co., Ltd. 4 | * 5 | * linux-cifsd-devel@lists.sourceforge.net 6 | */ 7 | 8 | #define _GNU_SOURCE 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "tools.h" 19 | #include "config_parser.h" 20 | 21 | #define PATH_CLASS_ATTR_KILL_SERVER "/sys/class/ksmbd-control/kill_server" 22 | #define PATH_CLASS_ATTR_DEBUG "/sys/class/ksmbd-control/debug" 23 | #define PATH_MODULE_VERSION "/sys/module/ksmbd/version" 24 | 25 | static void usage(int status) 26 | { 27 | printf( 28 | "Usage: ksmbd.control [-v] -s\n" 29 | " ksmbd.control [-v] -r\n" 30 | " ksmbd.control [-v] -l\n" 31 | " ksmbd.control [-v] -d COMPONENT\n" 32 | " ksmbd.control [-v] -c\n"); 33 | 34 | if (status != EXIT_SUCCESS) 35 | printf("Try `ksmbd.control --help' for more information.\n"); 36 | else 37 | printf( 38 | "\n" 39 | " -s, --shutdown shutdown both ksmbd.mountd and ksmbd and exit\n" 40 | " -r, --reload notify ksmbd.mountd of changes and exit\n" 41 | " -l, --list list ksmbd.mountd shares and exit\n" 42 | " -d, --debug=COMPONENT toggle ksmbd debug printing for COMPONENT and exit;\n" 43 | " COMPONENT is `all', `smb', `auth', `vfs', `oplock',\n" 44 | " `ipc', `conn', or `rdma';\n" 45 | " enabled ones are output enclosed in brackets (`[]')\n" 46 | " -c, --ksmbd-version output ksmbd version information and exit\n" 47 | " -v, --verbose be verbose\n" 48 | " -V, --version output version information and exit\n" 49 | " -h, --help display this help and exit\n" 50 | "\n" 51 | "See ksmbd.control(8) for more details.\n"); 52 | } 53 | 54 | static const struct option opts[] = { 55 | {"shutdown", no_argument, NULL, 's' }, 56 | {"reload", no_argument, NULL, 'r' }, 57 | {"list", no_argument, NULL, 'l' }, 58 | {"debug", required_argument, NULL, 'd' }, 59 | {"ksmbd-version", no_argument, NULL, 'c' }, 60 | {"verbose", no_argument, NULL, 'v' }, 61 | {"version", no_argument, NULL, 'V' }, 62 | {"help", no_argument, NULL, 'h' }, 63 | {NULL, 0, NULL, 0 } 64 | }; 65 | 66 | static int control_shutdown(void) 67 | { 68 | int ret, fd; 69 | 70 | ret = cp_parse_lock(); 71 | if (!ret && kill(global_conf.pid, SIGTERM) < 0) { 72 | ret = -errno; 73 | pr_debug("Can't send SIGTERM to PID %d: %m\n", 74 | global_conf.pid); 75 | } 76 | if (ret) 77 | pr_err("Can't terminate mountd\n"); 78 | else 79 | pr_info("Terminated mountd\n"); 80 | 81 | fd = open(PATH_CLASS_ATTR_KILL_SERVER, O_WRONLY); 82 | if (fd < 0) { 83 | ret = -errno; 84 | pr_debug("Can't open `%s': %m\n", 85 | PATH_CLASS_ATTR_KILL_SERVER); 86 | goto err_kill; 87 | } 88 | 89 | if (write(fd, "hard", sizeof("hard") - 1) < 0) { 90 | ret = -errno; 91 | pr_debug("Can't write `%s': %m\n", 92 | PATH_CLASS_ATTR_KILL_SERVER); 93 | close(fd); 94 | goto err_kill; 95 | } 96 | 97 | close(fd); 98 | pr_info("Killed ksmbd\n"); 99 | return ret; 100 | 101 | err_kill: 102 | pr_err("Can't kill ksmbd\n"); 103 | return ret; 104 | } 105 | 106 | static int control_reload(void) 107 | { 108 | int ret; 109 | 110 | ret = cp_parse_lock(); 111 | if (!ret && kill(global_conf.pid, SIGHUP) < 0) { 112 | ret = -errno; 113 | pr_debug("Can't send SIGHUP to PID %d: %m\n", 114 | global_conf.pid); 115 | } 116 | if (ret) 117 | pr_err("Can't notify mountd\n"); 118 | else 119 | pr_info("Notified mountd\n"); 120 | return ret; 121 | } 122 | 123 | static int control_list(void) 124 | { 125 | g_autofree char *fifo_path = 126 | g_strdup_printf("%s.%d", PATH_FIFO, getpid()); 127 | int ret, fd; 128 | sigset_t sigset; 129 | 130 | if (mkfifo(fifo_path, S_IRUSR | S_IWUSR) < 0) { 131 | ret = -errno; 132 | pr_debug("Can't create `%s': %m\n", fifo_path); 133 | goto out; 134 | } 135 | 136 | fd = open(fifo_path, O_RDONLY | O_NONBLOCK); 137 | if (fd < 0) { 138 | ret = -errno; 139 | pr_debug("Can't open `%s': %m\n", fifo_path); 140 | goto out_unlink; 141 | } 142 | 143 | if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_ASYNC) < 0 || 144 | fcntl(fd, F_SETOWN, getpid()) < 0) { 145 | ret = -errno; 146 | pr_debug("Can't control `%s': %m\n", fifo_path); 147 | goto out_close; 148 | } 149 | 150 | if (isatty(STDOUT_FILENO) && 151 | fcntl(STDOUT_FILENO, 152 | F_SETFL, 153 | fcntl(STDOUT_FILENO, F_GETFL) & ~O_APPEND) < 0) { 154 | ret = -errno; 155 | pr_debug("Can't control terminal: %m\n"); 156 | goto out_close; 157 | } 158 | 159 | ret = cp_parse_lock(); 160 | if (ret) 161 | goto out_close; 162 | 163 | sigemptyset(&sigset); 164 | sigaddset(&sigset, SIGIO); 165 | sigaddset(&sigset, SIGINT); 166 | sigaddset(&sigset, SIGQUIT); 167 | sigaddset(&sigset, SIGTERM); 168 | pthread_sigmask(SIG_BLOCK, &sigset, NULL); 169 | 170 | if (kill(global_conf.pid, SIGUSR1) < 0) { 171 | ret = -errno; 172 | pr_debug("Can't send SIGUSR1 to PID %d: %m\n", 173 | global_conf.pid); 174 | goto out_close; 175 | } 176 | 177 | for (;;) { 178 | siginfo_t siginfo; 179 | 180 | if (sigwaitinfo(&sigset, &siginfo) < 0) 181 | continue; 182 | 183 | if (siginfo.si_signo != SIGIO) 184 | goto out_close; 185 | 186 | for (;;) { 187 | int bytes_read = splice(fd, 188 | NULL, 189 | STDOUT_FILENO, 190 | NULL, 191 | PIPE_BUF, 192 | 0); 193 | 194 | if (bytes_read < 0) { 195 | if (errno == EAGAIN) 196 | break; 197 | ret = -errno; 198 | pr_debug("Can't splice pipe: %m\n"); 199 | goto out_close; 200 | } 201 | 202 | if (!bytes_read) 203 | goto out_close; 204 | } 205 | } 206 | 207 | out_close: 208 | close(fd); 209 | out_unlink: 210 | unlink(fifo_path); 211 | out: 212 | if (ret) 213 | pr_err("Can't list mountd shares\n"); 214 | else 215 | pr_info("Listed mountd shares\n"); 216 | return ret; 217 | } 218 | 219 | static int control_show_version(void) 220 | { 221 | g_autofree char *version = NULL; 222 | int fd, ret; 223 | off_t len; 224 | 225 | fd = open(PATH_MODULE_VERSION, O_RDONLY); 226 | if (fd < 0) { 227 | ret = -errno; 228 | pr_debug("Can't open `%s': %m\n", PATH_MODULE_VERSION); 229 | goto err; 230 | } 231 | 232 | len = lseek(fd, 0, SEEK_END); 233 | if (len == (off_t)-1 || lseek(fd, 0, SEEK_SET) == (off_t)-1) { 234 | ret = -errno; 235 | pr_debug("Can't seek `%s': %m\n", PATH_MODULE_VERSION); 236 | close(fd); 237 | goto err; 238 | } 239 | 240 | version = g_malloc0(len + 1); 241 | if (read(fd, version, len) < 0) { 242 | ret = -errno; 243 | pr_debug("Can't read `%s': %m\n", PATH_MODULE_VERSION); 244 | close(fd); 245 | goto err; 246 | } 247 | 248 | ret = 0; 249 | close(fd); 250 | pr_info("ksmbd version : " "%s", version); 251 | return ret; 252 | 253 | err: 254 | pr_err("Can't output ksmbd version\n"); 255 | return ret; 256 | } 257 | 258 | static int control_debug(char *comp) 259 | { 260 | g_autofree char *debug = NULL; 261 | int fd, ret; 262 | off_t len; 263 | 264 | fd = open(PATH_CLASS_ATTR_DEBUG, O_RDWR); 265 | if (fd < 0) { 266 | ret = -errno; 267 | pr_debug("Can't open `%s': %m\n", PATH_CLASS_ATTR_DEBUG); 268 | goto err; 269 | } 270 | 271 | if (write(fd, comp, strlen(comp)) < 0) { 272 | ret = -errno; 273 | pr_debug("Can't write `%s': %m\n", PATH_CLASS_ATTR_DEBUG); 274 | close(fd); 275 | goto err; 276 | } 277 | 278 | len = lseek(fd, 0, SEEK_END); 279 | if (len == (off_t)-1 || lseek(fd, 0, SEEK_SET) == (off_t)-1) { 280 | ret = -errno; 281 | pr_debug("Can't seek `%s': %m\n", PATH_CLASS_ATTR_DEBUG); 282 | close(fd); 283 | goto err; 284 | } 285 | 286 | debug = g_malloc0(len + 1); 287 | if (read(fd, debug, len) < 0) { 288 | ret = -errno; 289 | pr_debug("Can't read `%s': %m\n", PATH_CLASS_ATTR_DEBUG); 290 | close(fd); 291 | goto err; 292 | } 293 | 294 | ret = 0; 295 | close(fd); 296 | pr_info("%s", debug); 297 | return ret; 298 | 299 | err: 300 | pr_err("Can't toggle ksmbd debug component\n"); 301 | return ret; 302 | } 303 | 304 | int control_main(int argc, char **argv) 305 | { 306 | int ret = -EINVAL; 307 | int c; 308 | 309 | while ((c = getopt_long(argc, argv, "srld:cvVh", opts, NULL)) != EOF) 310 | switch (c) { 311 | case 's': 312 | ret = control_shutdown(); 313 | goto out; 314 | case 'r': 315 | ret = control_reload(); 316 | goto out; 317 | case 'l': 318 | ret = control_list(); 319 | goto out; 320 | case 'd': 321 | ret = control_debug(optarg); 322 | goto out; 323 | case 'c': 324 | ret = control_show_version(); 325 | goto out; 326 | case 'v': 327 | set_log_level(PR_DEBUG); 328 | break; 329 | case 'V': 330 | ret = show_version(); 331 | goto out; 332 | case 'h': 333 | ret = 0; 334 | /* Fall through */ 335 | case '?': 336 | default: 337 | usage(ret ? EXIT_FAILURE : EXIT_SUCCESS); 338 | goto out; 339 | } 340 | 341 | usage(ret ? EXIT_FAILURE : EXIT_SUCCESS); 342 | out: 343 | return ret ? EXIT_FAILURE : EXIT_SUCCESS; 344 | } 345 | -------------------------------------------------------------------------------- /tools/asn1.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * The ASB.1/BER parsing code is derived from ip_nat_snmp_basic.c which was in 4 | * turn derived from the gxsnmp package by Gregory McLean & Jochen Friedrich 5 | * 6 | * Copyright (c) 2000 RP Internet (www.rpi.net.au). 7 | */ 8 | 9 | /***************************************************************************** 10 | * 11 | * Basic ASN.1 decoding routines (gxsnmp author Dirk Wisse) 12 | * 13 | *****************************************************************************/ 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "asn1.h" 21 | 22 | void 23 | asn1_open(struct asn1_ctx *ctx, unsigned char *buf, unsigned int len) 24 | { 25 | ctx->begin = buf; 26 | ctx->end = buf + len; 27 | ctx->pointer = buf; 28 | ctx->error = ASN1_ERR_NOERROR; 29 | } 30 | 31 | static unsigned char 32 | asn1_octet_decode(struct asn1_ctx *ctx, unsigned char *ch) 33 | { 34 | if (ctx->pointer >= ctx->end) { 35 | ctx->error = ASN1_ERR_DEC_EMPTY; 36 | return 0; 37 | } 38 | *ch = *(ctx->pointer)++; 39 | return 1; 40 | } 41 | 42 | static unsigned char 43 | asn1_tag_decode(struct asn1_ctx *ctx, unsigned int *tag) 44 | { 45 | unsigned char ch; 46 | 47 | *tag = 0; 48 | 49 | do { 50 | if (!asn1_octet_decode(ctx, &ch)) 51 | return 0; 52 | *tag <<= 7; 53 | *tag |= ch & 0x7F; 54 | } while ((ch & 0x80) == 0x80); 55 | return 1; 56 | } 57 | 58 | static unsigned char 59 | asn1_id_decode(struct asn1_ctx *ctx, 60 | unsigned int *cls, unsigned int *con, unsigned int *tag) 61 | { 62 | unsigned char ch; 63 | 64 | if (!asn1_octet_decode(ctx, &ch)) 65 | return 0; 66 | 67 | *cls = (ch & 0xC0) >> 6; 68 | *con = (ch & 0x20) >> 5; 69 | *tag = (ch & 0x1F); 70 | 71 | if (*tag == 0x1F) { 72 | if (!asn1_tag_decode(ctx, tag)) 73 | return 0; 74 | } 75 | return 1; 76 | } 77 | 78 | static unsigned char 79 | asn1_length_decode(struct asn1_ctx *ctx, unsigned int *def, unsigned int *len) 80 | { 81 | unsigned char ch, cnt; 82 | 83 | if (!asn1_octet_decode(ctx, &ch)) 84 | return 0; 85 | 86 | if (ch == 0x80) 87 | *def = 0; 88 | else { 89 | *def = 1; 90 | 91 | if (ch < 0x80) 92 | *len = ch; 93 | else { 94 | cnt = (unsigned char) (ch & 0x7F); 95 | *len = 0; 96 | 97 | while (cnt > 0) { 98 | if (!asn1_octet_decode(ctx, &ch)) 99 | return 0; 100 | *len <<= 8; 101 | *len |= ch; 102 | cnt--; 103 | } 104 | } 105 | } 106 | 107 | /* don't trust len bigger than ctx buffer */ 108 | if (*len > ctx->end - ctx->pointer) 109 | return 0; 110 | 111 | return 1; 112 | } 113 | 114 | unsigned char 115 | asn1_header_decode(struct asn1_ctx *ctx, 116 | unsigned char **eoc, 117 | unsigned int *cls, unsigned int *con, unsigned int *tag) 118 | { 119 | unsigned int def = 0; 120 | unsigned int len = 0; 121 | 122 | if (!asn1_id_decode(ctx, cls, con, tag)) 123 | return 0; 124 | 125 | if (!asn1_length_decode(ctx, &def, &len)) 126 | return 0; 127 | 128 | /* primitive shall be definite, indefinite shall be constructed */ 129 | if (*con == ASN1_PRI && !def) 130 | return 0; 131 | 132 | if (def) 133 | *eoc = ctx->pointer + len; 134 | else 135 | *eoc = NULL; 136 | return 1; 137 | } 138 | 139 | static unsigned char 140 | asn1_eoc_decode(struct asn1_ctx *ctx, unsigned char *eoc) 141 | { 142 | unsigned char ch; 143 | 144 | if (eoc == NULL) { 145 | if (!asn1_octet_decode(ctx, &ch)) 146 | return 0; 147 | 148 | if (ch != 0x00) { 149 | ctx->error = ASN1_ERR_DEC_EOC_MISMATCH; 150 | return 0; 151 | } 152 | 153 | if (!asn1_octet_decode(ctx, &ch)) 154 | return 0; 155 | 156 | if (ch != 0x00) { 157 | ctx->error = ASN1_ERR_DEC_EOC_MISMATCH; 158 | return 0; 159 | } 160 | return 1; 161 | } 162 | 163 | if (ctx->pointer != eoc) { 164 | ctx->error = ASN1_ERR_DEC_LENGTH_MISMATCH; 165 | return 0; 166 | } 167 | return 1; 168 | } 169 | 170 | unsigned char 171 | asn1_octets_decode(struct asn1_ctx *ctx, 172 | unsigned char *eoc, 173 | unsigned char **octets, unsigned int *len) 174 | { 175 | unsigned char *ptr; 176 | 177 | *len = 0; 178 | 179 | *octets = g_try_malloc(eoc - ctx->pointer); 180 | if (!*octets) 181 | return 0; 182 | 183 | ptr = *octets; 184 | while (ctx->pointer < eoc) { 185 | if (!asn1_octet_decode(ctx, (unsigned char *) ptr++)) { 186 | g_free(*octets); 187 | *octets = NULL; 188 | return 0; 189 | } 190 | (*len)++; 191 | } 192 | return 1; 193 | } 194 | 195 | unsigned char asn1_read(struct asn1_ctx *ctx, 196 | unsigned char **buf, unsigned int len) 197 | { 198 | *buf = NULL; 199 | if (ctx->end - ctx->pointer < len) { 200 | ctx->error = ASN1_ERR_DEC_EMPTY; 201 | return 0; 202 | } 203 | 204 | *buf = g_try_malloc(len); 205 | if (!*buf) 206 | return 0; 207 | memcpy(*buf, ctx->pointer, len); 208 | ctx->pointer += len; 209 | return 1; 210 | } 211 | 212 | static unsigned char 213 | asn1_subid_decode(struct asn1_ctx *ctx, unsigned long *subid) 214 | { 215 | unsigned char ch; 216 | 217 | *subid = 0; 218 | 219 | do { 220 | if (!asn1_octet_decode(ctx, &ch)) 221 | return 0; 222 | 223 | *subid <<= 7; 224 | *subid |= ch & 0x7F; 225 | } while ((ch & 0x80) == 0x80); 226 | return 1; 227 | } 228 | 229 | int 230 | asn1_oid_decode(struct asn1_ctx *ctx, 231 | unsigned char *eoc, unsigned long **oid, unsigned int *len) 232 | { 233 | unsigned long subid; 234 | unsigned int size; 235 | unsigned long *optr; 236 | 237 | size = eoc - ctx->pointer + 1; 238 | 239 | /* first subid actually encodes first two subids */ 240 | if (size < 2 || size > UINT_MAX/sizeof(unsigned long)) 241 | return 0; 242 | 243 | *oid = g_try_malloc0_n(size, sizeof(unsigned long)); 244 | if (*oid == NULL) 245 | return 0; 246 | 247 | optr = *oid; 248 | 249 | if (!asn1_subid_decode(ctx, &subid)) { 250 | g_free(*oid); 251 | *oid = NULL; 252 | return 0; 253 | } 254 | 255 | if (subid < 40) { 256 | optr[0] = 0; 257 | optr[1] = subid; 258 | } else if (subid < 80) { 259 | optr[0] = 1; 260 | optr[1] = subid - 40; 261 | } else { 262 | optr[0] = 2; 263 | optr[1] = subid - 80; 264 | } 265 | 266 | *len = 2; 267 | optr += 2; 268 | 269 | while (ctx->pointer < eoc) { 270 | if (++(*len) > size) { 271 | ctx->error = ASN1_ERR_DEC_BADVALUE; 272 | g_free(*oid); 273 | *oid = NULL; 274 | return 0; 275 | } 276 | 277 | if (!asn1_subid_decode(ctx, optr++)) { 278 | g_free(*oid); 279 | *oid = NULL; 280 | return 0; 281 | } 282 | } 283 | return 1; 284 | } 285 | 286 | /* return the size of @depth-nested headers + payload */ 287 | int asn1_header_len(unsigned int payload_len, int depth) 288 | { 289 | unsigned int len; 290 | int i; 291 | 292 | len = payload_len; 293 | for (i = 0; i < depth; i++) { 294 | /* length */ 295 | if (len >= (1 << 24)) 296 | len += 5; 297 | else if (len >= (1 << 16)) 298 | len += 4; 299 | else if (len >= (1 << 8)) 300 | len += 3; 301 | else if (len >= (1 << 7)) 302 | len += 2; 303 | else 304 | len += 1; 305 | /* 1-byte header */ 306 | len += 1; 307 | } 308 | return len; 309 | } 310 | 311 | int asn1_oid_encode(const unsigned long *in_oid, int in_len, 312 | unsigned char **out_oid, int *out_len) 313 | { 314 | unsigned char *oid; 315 | unsigned long id; 316 | int i; 317 | 318 | *out_oid = g_try_malloc0_n(in_len, 5); 319 | if (*out_oid == NULL) 320 | return -ENOMEM; 321 | 322 | oid = *out_oid; 323 | *oid++ = (unsigned char)(40 * in_oid[0] + in_oid[1]); 324 | for (i = 2; i < in_len; i++) { 325 | id = in_oid[i]; 326 | if (id >= (1 << 28)) 327 | *oid++ = (0x80 | ((id>>28) & 0x7F)); 328 | if (id >= (1 << 21)) 329 | *oid++ = (0x80 | ((id>>21) & 0x7F)); 330 | if (id >= (1 << 14)) 331 | *oid++ = (0x80 | ((id>>14) & 0x7F)); 332 | if (id >= (1 << 7)) 333 | *oid++ = (0x80 | ((id>>7) & 0x7F)); 334 | *oid++ = id & 0x7F; 335 | } 336 | *out_len = (int)(oid - *out_oid); 337 | return 0; 338 | } 339 | 340 | /* 341 | * @len is the sum of all sizes of header, length and payload. 342 | * it will be decreased by the sum of sizes of header and length. 343 | */ 344 | int asn1_header_encode(unsigned char **buf, 345 | unsigned int cls, unsigned int con, unsigned int tag, 346 | unsigned int *len) 347 | { 348 | unsigned char *loc; 349 | unsigned int r_len; 350 | 351 | /* at least, 1-byte header + 1-byte length is needed. */ 352 | if (*len < 2) 353 | return -EINVAL; 354 | 355 | loc = *buf; 356 | r_len = *len; 357 | 358 | *loc++ = ((cls & 0x3) << 6) | ((con & 0x1) << 5) | (tag & 0x1F); 359 | r_len -= 1; 360 | 361 | if (r_len - 1 < (1 << 7)) { 362 | r_len -= 1; 363 | *loc++ = (unsigned char)(r_len & 0x7F); 364 | } else if (r_len - 2 < (1 << 8)) { 365 | r_len -= 2; 366 | *loc++ = 0x81; 367 | *loc++ = (unsigned char)(r_len & 0xFF); 368 | } else if (r_len - 3 < (1 << 16)) { 369 | r_len -= 3; 370 | *loc++ = 0x82; 371 | *loc++ = (unsigned char)((r_len>>8) & 0xFF); 372 | *loc++ = (unsigned char)(r_len & 0xFF); 373 | } else if (r_len - 4 < (1 << 24)) { 374 | r_len -= 4; 375 | *loc++ = 0x83; 376 | *loc++ = (unsigned char)((r_len>>16) & 0xFF); 377 | *loc++ = (unsigned char)((r_len>>8) & 0xFF); 378 | *loc++ = (unsigned char)(r_len & 0xFF); 379 | } else { 380 | r_len -= 5; 381 | *loc++ = 0x84; 382 | *loc++ = (unsigned char)((r_len>>24) & 0xFF); 383 | *loc++ = (unsigned char)((r_len>>16) & 0xFF); 384 | *loc++ = (unsigned char)((r_len>>8) & 0xFF); 385 | *loc++ = (unsigned char)(r_len & 0xFF); 386 | } 387 | 388 | *buf = loc; 389 | *len = r_len; 390 | return 0; 391 | } 392 | -------------------------------------------------------------------------------- /mountd/smbacl.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-2.1+ 2 | /* 3 | * Copyright (c) International Business Machines Corp., 2007 4 | * Author(s): Steve French (sfrench@us.ibm.com) 5 | * Copyright (C) 2020 Samsung Electronics Co., Ltd. 6 | * Author(s): Namjae Jeon (linkinjeon@kernel.org) 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | static const struct smb_sid sid_domain = {1, 1, {0, 0, 0, 0, 0, 5}, 15 | {21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; 16 | 17 | /* security id for everyone/world system group */ 18 | static const struct smb_sid sid_everyone = { 19 | 1, 1, {0, 0, 0, 0, 0, 1}, {0} }; 20 | 21 | /* S-1-22-1 Unmapped Unix users */ 22 | static const struct smb_sid sid_unix_users = {1, 1, {0, 0, 0, 0, 0, 22}, 23 | {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; 24 | 25 | /* S-1-22-2 Unmapped Unix groups */ 26 | static const struct smb_sid sid_unix_groups = { 1, 1, {0, 0, 0, 0, 0, 22}, 27 | {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; 28 | 29 | /* security id for local group */ 30 | static const struct smb_sid sid_local_group = { 31 | 1, 1, {0, 0, 0, 0, 0, 5}, {32} }; 32 | 33 | int smb_read_sid(struct ksmbd_dcerpc *dce, struct smb_sid *sid) 34 | { 35 | int i; 36 | 37 | if (ndr_read_int8(dce, &sid->revision)) 38 | return -EINVAL; 39 | if (ndr_read_int8(dce, &sid->num_subauth)) 40 | return -EINVAL; 41 | if (!sid->num_subauth || sid->num_subauth >= SID_MAX_SUB_AUTHORITIES) 42 | return -EINVAL; 43 | for (i = 0; i < NUM_AUTHS; ++i) 44 | if (ndr_read_int8(dce, &sid->authority[i])) 45 | return -EINVAL; 46 | for (i = 0; i < sid->num_subauth; ++i) 47 | if (ndr_read_int32(dce, &sid->sub_auth[i])) 48 | return -EINVAL; 49 | return 0; 50 | } 51 | 52 | int smb_write_sid(struct ksmbd_dcerpc *dce, const struct smb_sid *src) 53 | { 54 | int i; 55 | 56 | if (ndr_write_int8(dce, src->revision)) 57 | return -ENOMEM; 58 | 59 | if (ndr_write_int8(dce, src->num_subauth)) 60 | return -ENOMEM; 61 | 62 | for (i = 0; i < NUM_AUTHS; ++i) { 63 | if (ndr_write_int8(dce, src->authority[i])) 64 | return -ENOMEM; 65 | } 66 | for (i = 0; i < src->num_subauth; ++i) { 67 | if (ndr_write_int32(dce, src->sub_auth[i])) 68 | return -ENOMEM; 69 | } 70 | 71 | return 0; 72 | } 73 | 74 | void smb_copy_sid(struct smb_sid *dst, const struct smb_sid *src) 75 | { 76 | int i; 77 | 78 | dst->revision = src->revision; 79 | dst->num_subauth = src->num_subauth; 80 | for (i = 0; i < NUM_AUTHS; ++i) 81 | dst->authority[i] = src->authority[i]; 82 | for (i = 0; i < dst->num_subauth; ++i) 83 | dst->sub_auth[i] = src->sub_auth[i]; 84 | } 85 | 86 | void smb_init_domain_sid(struct smb_sid *sid) 87 | { 88 | int i; 89 | 90 | memset(sid, 0, sizeof(struct smb_sid)); 91 | sid->revision = 1; 92 | sid->num_subauth = 4; 93 | sid->authority[5] = 5; 94 | sid->sub_auth[0] = 21; 95 | for (i = 0; i < 3; i++) 96 | sid->sub_auth[i+1] = global_conf.gen_subauth[i]; 97 | } 98 | 99 | int smb_compare_sids(const struct smb_sid *ctsid, const struct smb_sid *cwsid) 100 | { 101 | int i; 102 | int num_subauth, num_sat, num_saw; 103 | 104 | if ((!ctsid) || (!cwsid)) 105 | return 1; 106 | 107 | /* compare the revision */ 108 | if (ctsid->revision != cwsid->revision) { 109 | if (ctsid->revision > cwsid->revision) 110 | return 1; 111 | return -1; 112 | } 113 | 114 | /* compare all of the six auth values */ 115 | for (i = 0; i < NUM_AUTHS; ++i) { 116 | if (ctsid->authority[i] != cwsid->authority[i]) { 117 | if (ctsid->authority[i] > cwsid->authority[i]) 118 | return 1; 119 | return -1; 120 | } 121 | } 122 | 123 | /* compare all of the subauth values if any */ 124 | num_sat = ctsid->num_subauth; 125 | num_saw = cwsid->num_subauth; 126 | num_subauth = num_sat < num_saw ? num_sat : num_saw; 127 | if (num_subauth) { 128 | for (i = 0; i < num_subauth; ++i) { 129 | if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) { 130 | if (ctsid->sub_auth[i] > 131 | cwsid->sub_auth[i]) 132 | return 1; 133 | return -1; 134 | } 135 | } 136 | } 137 | 138 | return 0; /* sids compare/match */ 139 | } 140 | 141 | static int smb_sid_to_string(char *domain, size_t domain_len, 142 | struct smb_sid *sid) 143 | { 144 | int i, len; 145 | 146 | len = snprintf(domain, domain_len, "S-%i-%i", (int)sid->revision, 147 | (int)sid->authority[5]); 148 | 149 | if (len < 0 || len > domain_len) 150 | return -ENOMEM; 151 | 152 | for (i = 0; i < sid->num_subauth; i++) { 153 | len += snprintf(domain + len, domain_len - len, "-%u", 154 | sid->sub_auth[i]); 155 | if (len < 0 || len > domain_len) 156 | return -ENOMEM; 157 | } 158 | 159 | return len; 160 | } 161 | 162 | int set_domain_name(struct smb_sid *sid, char *domain, size_t domain_len, 163 | int *type) 164 | { 165 | int ret = 0; 166 | char domain_string[DOMAIN_STR_SIZE] = {0}; 167 | g_autofree char *domain_name = NULL; 168 | 169 | if (!smb_compare_sids(sid, &sid_domain) && 170 | !memcmp(&sid->sub_auth[1], global_conf.gen_subauth, 171 | sizeof(__u32) * 3)) { 172 | if (gethostname(domain_string, DOMAIN_STR_SIZE)) 173 | return -ENOMEM; 174 | 175 | domain_name = g_ascii_strup(domain_string, -1); 176 | if (!domain_name) 177 | return -ENOMEM; 178 | 179 | ret = snprintf(domain, domain_len, "%s", domain_name); 180 | if (ret < 0 || ret >= domain_len) 181 | return -ENOMEM; 182 | 183 | *type = SID_TYPE_USER; 184 | } else if (!smb_compare_sids(sid, &sid_unix_users)) { 185 | ret = snprintf(domain, domain_len, "Unix User"); 186 | if (ret < 0 || ret >= domain_len) 187 | return -ENOMEM; 188 | 189 | *type = SID_TYPE_USER; 190 | } else if (!smb_compare_sids(sid, &sid_unix_groups)) { 191 | ret = snprintf(domain, domain_len, "Unix Group"); 192 | if (ret < 0 || ret >= domain_len) 193 | return -ENOMEM; 194 | 195 | *type = SID_TYPE_GROUP; 196 | } else { 197 | ret = smb_sid_to_string(domain_string, sizeof(domain_string), 198 | sid); 199 | if (ret < 0) 200 | return ret; 201 | 202 | if (ret > domain_len) 203 | return -ENOMEM; 204 | 205 | domain_name = g_ascii_strup(domain_string, -1); 206 | if (!domain_name) 207 | return -ENOMEM; 208 | 209 | ret = snprintf(domain, domain_len, "%s", domain_name); 210 | if (ret < 0 || ret >= domain_len) 211 | return -ENOMEM; 212 | 213 | *type = SID_TYPE_UNKNOWN; 214 | ret = -ENOENT; 215 | } 216 | return ret; 217 | } 218 | 219 | static int smb_set_ace(struct ksmbd_dcerpc *dce, int access_req, int rid, 220 | const struct smb_sid *rsid) 221 | { 222 | int size; 223 | struct smb_sid sid = {0}; 224 | 225 | memcpy(&sid, rsid, sizeof(struct smb_sid)); 226 | // ace type 227 | if (ndr_write_int8(dce, ACCESS_ALLOWED)) 228 | return -ENOMEM; 229 | 230 | // ace flags 231 | if (ndr_write_int8(dce, 0)) 232 | return -ENOMEM; 233 | 234 | size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (sid.num_subauth * 4); 235 | if (rid) 236 | size += 4; 237 | 238 | // ace size 239 | if (ndr_write_int16(dce, size)) 240 | return -ENOMEM; 241 | 242 | // ace access required 243 | if (ndr_write_int32(dce, access_req)) 244 | return -ENOMEM; 245 | 246 | if (rid) 247 | sid.sub_auth[sid.num_subauth++] = rid; 248 | 249 | if (smb_write_sid(dce, &sid)) 250 | return -ENOMEM; 251 | 252 | return size; 253 | } 254 | 255 | static int set_dacl(struct ksmbd_dcerpc *dce, int rid) 256 | { 257 | int size = 0, i, ret; 258 | struct smb_sid owner_domain; 259 | 260 | /* Other */ 261 | ret = smb_set_ace(dce, 0x0002035b, 0, &sid_everyone); 262 | if (ret < 0) 263 | return ret; 264 | size += ret; 265 | 266 | /* Local Group Administrators */ 267 | ret = smb_set_ace(dce, 0x000f07ff, 544, &sid_local_group); 268 | if (ret < 0) 269 | return ret; 270 | size += ret; 271 | 272 | /* Local Group Account Operators */ 273 | ret = smb_set_ace(dce, 0x000f07ff, 548, &sid_local_group); 274 | if (ret < 0) 275 | return ret; 276 | size += ret; 277 | 278 | /* Owner RID */ 279 | memcpy(&owner_domain, &sid_domain, sizeof(struct smb_sid)); 280 | for (i = 0; i < 3; ++i) { 281 | owner_domain.sub_auth[i + 1] = global_conf.gen_subauth[i]; 282 | owner_domain.num_subauth++; 283 | } 284 | 285 | ret = smb_set_ace(dce, 0x00020044, rid, &owner_domain); 286 | if (ret < 0) 287 | return ret; 288 | size += ret; 289 | 290 | return size; 291 | } 292 | 293 | int build_sec_desc(struct ksmbd_dcerpc *dce, __u32 *secdesclen, int rid) 294 | { 295 | int l_offset, acl_size_offset; 296 | int acl_size; 297 | 298 | /* NT Security Descriptor : Revision */ 299 | if (ndr_write_int16(dce, 1)) 300 | return -ENOMEM; 301 | 302 | /* ACL Type */ 303 | if (ndr_write_int16(dce, SELF_RELATIVE | DACL_PRESENT)) 304 | return -ENOMEM; 305 | 306 | /* Offset to owner SID */ 307 | if (ndr_write_int32(dce, 0)) 308 | return -ENOMEM; 309 | 310 | /* Offset to group SID */ 311 | if (ndr_write_int32(dce, 0)) 312 | return -ENOMEM; 313 | 314 | /* Offset to SACL */ 315 | if (ndr_write_int32(dce, 0)) 316 | return -ENOMEM; 317 | 318 | /* Offset to DACL */ 319 | if (ndr_write_int32(dce, sizeof(struct smb_ntsd))) 320 | return -ENOMEM; 321 | 322 | /* DACL Revision */ 323 | if (ndr_write_int16(dce, 2)) 324 | return -ENOMEM; 325 | 326 | acl_size_offset = dce->offset; 327 | dce->offset += 2; 328 | 329 | /* Number of ACEs */ 330 | if (ndr_write_int32(dce, 4)) 331 | return -ENOMEM; 332 | 333 | acl_size = set_dacl(dce, rid) + sizeof(struct smb_acl); 334 | if (acl_size < 0) 335 | return -ENOMEM; 336 | /* ACL Size */ 337 | l_offset = dce->offset; 338 | dce->offset = acl_size_offset; 339 | if (ndr_write_int16(dce, acl_size)) 340 | return -ENOMEM; 341 | dce->offset = l_offset; 342 | 343 | *secdesclen = sizeof(struct smb_ntsd) + acl_size; 344 | return 0; 345 | } 346 | -------------------------------------------------------------------------------- /tools/management/spnego.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * Copyright (C) 2020 LG Electronics 4 | * 5 | * linux-cifsd-devel@lists.sourceforge.net 6 | */ 7 | 8 | #include "tools.h" 9 | 10 | #ifndef _GNU_SOURCE 11 | #define _GNU_SOURCE 12 | #endif 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include "spnego_mech.h" 26 | 27 | static struct spnego_mech_ctx mech_ctxs[SPNEGO_MAX_MECHS]; 28 | 29 | static struct spnego_mech_ctx *get_mech(int mech_type) 30 | { 31 | if (mech_type >= SPNEGO_MAX_MECHS) 32 | return NULL; 33 | return &mech_ctxs[mech_type]; 34 | } 35 | 36 | void spnego_init(void) 37 | { 38 | struct spnego_mech_ctx *mech_ctx; 39 | int i; 40 | 41 | mech_ctx = &mech_ctxs[SPNEGO_MECH_MSKRB5]; 42 | if (!mech_ctx->ops) 43 | mech_ctx->ops = &spnego_mskrb5_operations; 44 | if (!mech_ctx->params.krb5.service_name) 45 | mech_ctx->params.krb5.service_name = 46 | g_strdup(global_conf.krb5_service_name); 47 | if (!mech_ctx->params.krb5.keytab_name) 48 | mech_ctx->params.krb5.keytab_name = 49 | g_strdup(global_conf.krb5_keytab_file); 50 | 51 | mech_ctx = &mech_ctxs[SPNEGO_MECH_KRB5]; 52 | if (!mech_ctx->ops) 53 | mech_ctx->ops = &spnego_krb5_operations; 54 | if (!mech_ctx->params.krb5.service_name) 55 | mech_ctx->params.krb5.service_name = 56 | g_strdup(global_conf.krb5_service_name); 57 | if (!mech_ctx->params.krb5.keytab_name) 58 | mech_ctx->params.krb5.keytab_name = 59 | g_strdup(global_conf.krb5_keytab_file); 60 | 61 | for (i = 0; i < SPNEGO_MAX_MECHS; i++) 62 | if (mech_ctxs[i].ops->setup && 63 | mech_ctxs[i].ops->setup(&mech_ctxs[i])) 64 | abort(); 65 | } 66 | 67 | void spnego_destroy(void) 68 | { 69 | int i; 70 | 71 | for (i = 0; i < SPNEGO_MAX_MECHS; i++) { 72 | if (mech_ctxs[i].ops && mech_ctxs[i].ops->cleanup) 73 | mech_ctxs[i].ops->cleanup(&mech_ctxs[i]); 74 | } 75 | } 76 | 77 | static int compare_oid(unsigned long *oid1, unsigned int oid1len, 78 | unsigned long *oid2, unsigned int oid2len) 79 | { 80 | unsigned int i; 81 | 82 | if (oid1len != oid2len) 83 | return 1; 84 | 85 | for (i = 0; i < oid1len; i++) { 86 | if (oid1[i] != oid2[i]) 87 | return 1; 88 | } 89 | return 0; 90 | } 91 | 92 | static bool is_supported_mech(unsigned long *oid, unsigned int len, 93 | int *mech_type) 94 | { 95 | if (!compare_oid(oid, len, MSKRB5_OID, ARRAY_SIZE(MSKRB5_OID))) { 96 | *mech_type = SPNEGO_MECH_MSKRB5; 97 | return true; 98 | } 99 | 100 | if (!compare_oid(oid, len, KRB5_OID, ARRAY_SIZE(KRB5_OID))) { 101 | *mech_type = SPNEGO_MECH_KRB5; 102 | return true; 103 | } 104 | 105 | *mech_type = SPNEGO_MAX_MECHS; 106 | return false; 107 | } 108 | 109 | static int decode_asn1_header(struct asn1_ctx *ctx, unsigned char **end, 110 | unsigned int cls, unsigned int con, unsigned int tag) 111 | { 112 | unsigned int d_cls, d_con, d_tag; 113 | 114 | if (asn1_header_decode(ctx, end, &d_cls, &d_con, &d_tag) == 0 || 115 | (d_cls != cls || d_con != con || d_tag != tag)) 116 | return -EINVAL; 117 | return 0; 118 | } 119 | 120 | static int decode_negTokenInit(unsigned char *negToken, int token_len, 121 | int *mech_type, unsigned char **krb5_ap_req, 122 | unsigned int *req_len) 123 | { 124 | struct asn1_ctx ctx; 125 | unsigned char *end, *mech_types_end, *id; 126 | unsigned long *oid = NULL; 127 | unsigned int len; 128 | 129 | asn1_open(&ctx, negToken, token_len); 130 | 131 | /* GSSAPI header */ 132 | if (decode_asn1_header(&ctx, &end, ASN1_APL, ASN1_CON, ASN1_EOC)) { 133 | pr_debug("Error decoding SPNEGO application tag\n"); 134 | return -EINVAL; 135 | } 136 | 137 | /* SPNEGO oid */ 138 | if (decode_asn1_header(&ctx, &end, ASN1_UNI, ASN1_PRI, ASN1_OJI) || 139 | asn1_oid_decode(&ctx, end, &oid, &len) == 0 || 140 | compare_oid(oid, len, SPNEGO_OID, SPNEGO_OID_LEN)) { 141 | pr_debug("Error decoding SPNEGO OID\n"); 142 | g_free(oid); 143 | return -EINVAL; 144 | } 145 | g_free(oid); 146 | 147 | /* negoTokenInit */ 148 | if (decode_asn1_header(&ctx, &end, ASN1_CTX, ASN1_CON, 0) || 149 | decode_asn1_header(&ctx, &end, 150 | ASN1_UNI, ASN1_CON, ASN1_SEQ)) { 151 | pr_debug("Error decoding negTokenInit tag\n"); 152 | return -EINVAL; 153 | } 154 | 155 | /* mechTypes */ 156 | if (decode_asn1_header(&ctx, &end, ASN1_CTX, ASN1_CON, 0) || 157 | decode_asn1_header(&ctx, &end, 158 | ASN1_UNI, ASN1_CON, ASN1_SEQ)) { 159 | pr_debug("Error decoding mechTypes tag\n"); 160 | return -EINVAL; 161 | } 162 | 163 | mech_types_end = end; 164 | if (decode_asn1_header(&ctx, &end, ASN1_UNI, ASN1_PRI, ASN1_OJI) || 165 | asn1_oid_decode(&ctx, end, &oid, &len) == 0) { 166 | pr_debug("Error decoding Kerberos 5 OIDs\n"); 167 | return -EINVAL; 168 | } 169 | 170 | if (!is_supported_mech(oid, len, mech_type)) { 171 | g_free(oid); 172 | pr_debug("Not a supported mechanism\n"); 173 | return -EINVAL; 174 | } 175 | g_free(oid); 176 | 177 | ctx.pointer = mech_types_end; 178 | /* mechToken */ 179 | if (decode_asn1_header(&ctx, &end, ASN1_CTX, ASN1_CON, 2) || 180 | decode_asn1_header(&ctx, &end, 181 | ASN1_UNI, ASN1_PRI, ASN1_OTS)) { 182 | pr_debug("Error decoding krb5_blob\n"); 183 | return -EINVAL; 184 | } 185 | 186 | if (decode_asn1_header(&ctx, &end, ASN1_APL, ASN1_CON, ASN1_EOC)) { 187 | pr_debug("Error decoding GSSAPI application tag\n"); 188 | return -EINVAL; 189 | } 190 | 191 | /* Kerberos 5 oid */ 192 | if (decode_asn1_header(&ctx, &end, ASN1_UNI, ASN1_PRI, ASN1_OJI)) { 193 | pr_debug("Error decoding Kerberos 5 OID tag\n"); 194 | return -EINVAL; 195 | } 196 | 197 | if (asn1_oid_decode(&ctx, end, &oid, &len) == 0 || 198 | compare_oid(oid, len, KRB5_OID, 199 | ARRAY_SIZE(KRB5_OID))) { 200 | pr_debug("Not a Kerberos 5 OID\n"); 201 | g_free(oid); 202 | return -EINVAL; 203 | } 204 | g_free(oid); 205 | 206 | /* AP_REQ id */ 207 | if (asn1_read(&ctx, &id, 2) == 0 || id[0] != 1 || id[1] != 0) { 208 | g_free(id); 209 | pr_debug("Error decoding AP_REQ ID\n"); 210 | return -EINVAL; 211 | } 212 | g_free(id); 213 | 214 | /* AP_REQ */ 215 | *req_len = (unsigned int)(ctx.end - ctx.pointer); 216 | *krb5_ap_req = ctx.pointer; 217 | return 0; 218 | } 219 | 220 | static int encode_negTokenTarg(char *in_blob, int in_len, 221 | const unsigned long *oid, int oid_len, 222 | char **out_blob, int *out_len) 223 | { 224 | unsigned char *buf; 225 | unsigned char *sup_oid, *krb5_oid; 226 | int sup_oid_len, krb5_oid_len; 227 | unsigned int neg_result_len, sup_mech_len, rep_token_len, len; 228 | 229 | if (asn1_oid_encode(oid, oid_len, &sup_oid, &sup_oid_len)) 230 | return -ENOMEM; 231 | if (asn1_oid_encode(KRB5_OID, ARRAY_SIZE(KRB5_OID), 232 | &krb5_oid, &krb5_oid_len)) { 233 | g_free(sup_oid); 234 | return -ENOMEM; 235 | } 236 | 237 | neg_result_len = asn1_header_len(1, 2); 238 | sup_mech_len = asn1_header_len(sup_oid_len, 2); 239 | rep_token_len = asn1_header_len(krb5_oid_len, 1); 240 | rep_token_len += 2 + in_len; 241 | rep_token_len = asn1_header_len(rep_token_len, 3); 242 | 243 | *out_len = asn1_header_len( 244 | neg_result_len + sup_mech_len + rep_token_len, 2); 245 | *out_blob = g_try_malloc0(*out_len); 246 | if (*out_blob == NULL) 247 | return -ENOMEM; 248 | buf = *out_blob; 249 | 250 | /* negTokenTarg */ 251 | len = *out_len; 252 | asn1_header_encode(&buf, 253 | ASN1_CTX, ASN1_CON, 1, 254 | &len); 255 | asn1_header_encode(&buf, 256 | ASN1_UNI, ASN1_CON, ASN1_SEQ, 257 | &len); 258 | 259 | /* negTokenTarg/negResult */ 260 | len = neg_result_len; 261 | asn1_header_encode(&buf, 262 | ASN1_CTX, ASN1_CON, 0, 263 | &len); 264 | asn1_header_encode(&buf, 265 | ASN1_UNI, ASN1_PRI, ASN1_ENUM, 266 | &len); 267 | *buf++ = 0; 268 | 269 | /* negTokenTarg/supportedMechType */ 270 | len = sup_mech_len; 271 | asn1_header_encode(&buf, 272 | ASN1_CTX, ASN1_CON, 1, 273 | &len); 274 | asn1_header_encode(&buf, 275 | ASN1_UNI, ASN1_PRI, ASN1_OJI, 276 | &len); 277 | memcpy(buf, sup_oid, sup_oid_len); 278 | buf += len; 279 | 280 | /* negTokenTarg/responseToken */ 281 | len = rep_token_len; 282 | asn1_header_encode(&buf, 283 | ASN1_CTX, ASN1_CON, 2, 284 | &len); 285 | asn1_header_encode(&buf, 286 | ASN1_UNI, ASN1_PRI, ASN1_OTS, 287 | &len); 288 | asn1_header_encode(&buf, 289 | ASN1_APL, ASN1_CON, 0, 290 | &len); 291 | /* negTokenTarg/responseToken/OID */ 292 | len = asn1_header_len(krb5_oid_len, 1); 293 | asn1_header_encode(&buf, 294 | ASN1_UNI, ASN1_PRI, ASN1_OJI, 295 | &len); 296 | /* negTokenTarg/responseToken/mechToken*/ 297 | memcpy(buf, krb5_oid, krb5_oid_len); 298 | buf += len; 299 | /* AP_REP id */ 300 | *buf++ = 2; 301 | *buf++ = 0; 302 | memcpy(buf, in_blob, in_len); 303 | 304 | g_free(sup_oid); 305 | g_free(krb5_oid); 306 | return 0; 307 | } 308 | 309 | int spnego_handle_authen_request(struct ksmbd_spnego_authen_request *req, 310 | struct ksmbd_spnego_auth_out *auth_out) 311 | { 312 | struct spnego_mech_ctx *mech_ctx; 313 | unsigned char *mech_token; 314 | int token_len, mech_type; 315 | int retval = 0; 316 | 317 | if (decode_negTokenInit(req->spnego_blob, (int)req->spnego_blob_len, 318 | &mech_type, &mech_token, &token_len)) { 319 | pr_info("Error decoding negTokenInit\n"); 320 | return -EINVAL; 321 | } 322 | 323 | mech_ctx = get_mech(mech_type); 324 | if (!mech_ctx) { 325 | retval = -ENOTSUP; 326 | pr_info("No support for Kerberos 5\n"); 327 | goto out; 328 | } 329 | 330 | if (mech_ctx->ops->handle_authen(mech_ctx, 331 | mech_token, token_len, 332 | auth_out, encode_negTokenTarg)) { 333 | retval = -EPERM; 334 | pr_info("Error authenticating\n"); 335 | goto out; 336 | } 337 | out: 338 | return retval; 339 | } 340 | -------------------------------------------------------------------------------- /include/linux/ksmbd_server.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /* 3 | * Copyright (C) 2018 Samsung Electronics Co., Ltd. 4 | * 5 | * linux-ksmbd-devel@lists.sourceforge.net 6 | */ 7 | 8 | #ifndef _LINUX_KSMBD_SERVER_H 9 | #define _LINUX_KSMBD_SERVER_H 10 | 11 | #include 12 | 13 | #define KSMBD_GENL_NAME "SMBD_GENL" 14 | #define KSMBD_GENL_VERSION 0x01 15 | 16 | #define KSMBD_REQ_MAX_ACCOUNT_NAME_SZ 48 17 | #define KSMBD_REQ_MAX_HASH_SZ 18 18 | #define KSMBD_REQ_MAX_SHARE_NAME 64 19 | 20 | struct ksmbd_heartbeat { 21 | __u32 handle; 22 | }; 23 | 24 | /* 25 | * Global config flags. 26 | */ 27 | #define KSMBD_GLOBAL_FLAG_INVALID (0) 28 | #define KSMBD_GLOBAL_FLAG_SMB2_LEASES (1 << 0) 29 | #define KSMBD_GLOBAL_FLAG_SMB3_ENCRYPTION (1 << 1) 30 | #define KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL (1 << 2) 31 | #define KSMBD_GLOBAL_FLAG_SMB3_ENCRYPTION_OFF (1 << 3) 32 | #define KSMBD_GLOBAL_FLAG_DURABLE_HANDLES (1 << 4) 33 | 34 | struct ksmbd_startup_request { 35 | __u32 flags; 36 | __s32 signing; 37 | __s8 min_prot[16]; 38 | __s8 max_prot[16]; 39 | __s8 netbios_name[16]; 40 | __s8 work_group[64]; 41 | __s8 server_string[64]; 42 | __u16 tcp_port; 43 | __u16 ipc_timeout; 44 | __u32 deadtime; 45 | __u32 file_max; 46 | __u32 smb2_max_write; 47 | __u32 smb2_max_read; 48 | __u32 smb2_max_trans; 49 | __u32 share_fake_fscaps; 50 | __u32 sub_auth[3]; 51 | __u32 smb2_max_credits; 52 | __u32 smbd_max_io_size; /* smbd read write size */ 53 | __u32 max_connections; /* Number of maximum simultaneous connections */ 54 | __s8 bind_interfaces_only; 55 | __u32 max_ip_connections; /* Number of maximum connection per ip address */ 56 | __s8 reserved[499]; /* Reserved room */ 57 | __u32 ifc_list_sz; 58 | __s8 ____payload[]; 59 | } __attribute__((packed)); 60 | 61 | #define KSMBD_STARTUP_CONFIG_INTERFACES(s) ((s)->____payload) 62 | 63 | struct ksmbd_shutdown_request { 64 | __s32 reserved[16]; 65 | }; 66 | 67 | struct ksmbd_login_request { 68 | __u32 handle; 69 | __s8 account[KSMBD_REQ_MAX_ACCOUNT_NAME_SZ]; 70 | __u32 reserved[16]; /* Reserved room */ 71 | }; 72 | 73 | struct ksmbd_login_response { 74 | __u32 handle; 75 | __u32 gid; 76 | __u32 uid; 77 | __s8 account[KSMBD_REQ_MAX_ACCOUNT_NAME_SZ]; 78 | __u16 status; 79 | __u16 hash_sz; 80 | __s8 hash[KSMBD_REQ_MAX_HASH_SZ]; 81 | __u32 reserved[16]; /* Reserved room */ 82 | }; 83 | 84 | /* 85 | * IPC user login response extension. 86 | */ 87 | struct ksmbd_login_response_ext { 88 | __u32 handle; 89 | __s32 ngroups; /* supplementary group count */ 90 | __s8 reserved[128]; /* Reserved room */ 91 | __s8 ____payload[]; 92 | }; 93 | 94 | struct ksmbd_share_config_request { 95 | __u32 handle; 96 | __s8 share_name[KSMBD_REQ_MAX_SHARE_NAME]; 97 | __u32 reserved[16]; /* Reserved room */ 98 | }; 99 | 100 | struct ksmbd_share_config_response { 101 | __u32 handle; 102 | __u32 flags; 103 | __u16 create_mask; 104 | __u16 directory_mask; 105 | __u16 force_create_mode; 106 | __u16 force_directory_mode; 107 | __u16 force_uid; 108 | __u16 force_gid; 109 | __s8 share_name[KSMBD_REQ_MAX_SHARE_NAME]; 110 | __u32 reserved[111]; /* Reserved room */ 111 | __u32 payload_sz; 112 | __u32 veto_list_sz; 113 | __s8 ____payload[]; 114 | }; 115 | 116 | #define KSMBD_SHARE_CONFIG_VETO_LIST(s) ((s)->____payload) 117 | #define KSMBD_SHARE_CONFIG_PATH(s) \ 118 | ({ \ 119 | char *p = (s)->____payload; \ 120 | if ((s)->veto_list_sz) \ 121 | p += (s)->veto_list_sz + 1; \ 122 | p; \ 123 | }) 124 | 125 | struct ksmbd_tree_connect_request { 126 | __u32 handle; 127 | __u16 account_flags; 128 | __u16 flags; 129 | __u64 session_id; 130 | __u64 connect_id; 131 | __s8 account[KSMBD_REQ_MAX_ACCOUNT_NAME_SZ]; 132 | __s8 share[KSMBD_REQ_MAX_SHARE_NAME]; 133 | __s8 peer_addr[64]; 134 | __u32 reserved[16]; /* Reserved room */ 135 | }; 136 | 137 | struct ksmbd_tree_connect_response { 138 | __u32 handle; 139 | __u16 status; 140 | __u16 connection_flags; 141 | __u32 reserved[16]; /* Reserved room */ 142 | }; 143 | 144 | struct ksmbd_tree_disconnect_request { 145 | __u64 session_id; 146 | __u64 connect_id; 147 | __u32 reserved[16]; /* Reserved room */ 148 | }; 149 | 150 | struct ksmbd_logout_request { 151 | __s8 account[KSMBD_REQ_MAX_ACCOUNT_NAME_SZ]; 152 | __u32 account_flags; 153 | __u32 reserved[16]; /* Reserved room */ 154 | }; 155 | 156 | struct ksmbd_rpc_command { 157 | __u32 handle; 158 | __u32 flags; 159 | __u32 payload_sz; 160 | __u8 payload[]; 161 | }; 162 | 163 | struct ksmbd_spnego_authen_request { 164 | __u32 handle; 165 | __u16 spnego_blob_len; 166 | __u8 spnego_blob[]; 167 | }; 168 | 169 | struct ksmbd_spnego_authen_response { 170 | __u32 handle; 171 | struct ksmbd_login_response login_response; 172 | __u16 session_key_len; 173 | __u16 spnego_blob_len; 174 | __u8 payload[]; 175 | }; 176 | 177 | /* 178 | * This also used as NETLINK attribute type value. 179 | * 180 | * NOTE: 181 | * Response message type value should be equal to 182 | * request message type value + 1. 183 | */ 184 | enum ksmbd_event { 185 | KSMBD_EVENT_UNSPEC = 0, 186 | KSMBD_EVENT_HEARTBEAT_REQUEST, 187 | 188 | KSMBD_EVENT_STARTING_UP, 189 | KSMBD_EVENT_SHUTTING_DOWN, 190 | 191 | KSMBD_EVENT_LOGIN_REQUEST, 192 | KSMBD_EVENT_LOGIN_RESPONSE = 5, 193 | 194 | KSMBD_EVENT_SHARE_CONFIG_REQUEST, 195 | KSMBD_EVENT_SHARE_CONFIG_RESPONSE, 196 | 197 | KSMBD_EVENT_TREE_CONNECT_REQUEST, 198 | KSMBD_EVENT_TREE_CONNECT_RESPONSE, 199 | 200 | KSMBD_EVENT_TREE_DISCONNECT_REQUEST = 10, 201 | 202 | KSMBD_EVENT_LOGOUT_REQUEST, 203 | 204 | KSMBD_EVENT_RPC_REQUEST, 205 | KSMBD_EVENT_RPC_RESPONSE, 206 | 207 | KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST, 208 | KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE = 15, 209 | 210 | KSMBD_EVENT_LOGIN_REQUEST_EXT, 211 | KSMBD_EVENT_LOGIN_RESPONSE_EXT, 212 | 213 | KSMBD_EVENT_MAX 214 | }; 215 | 216 | enum KSMBD_TREE_CONN_STATUS { 217 | KSMBD_TREE_CONN_STATUS_OK = 0, 218 | KSMBD_TREE_CONN_STATUS_NOMEM, 219 | KSMBD_TREE_CONN_STATUS_NO_SHARE, 220 | KSMBD_TREE_CONN_STATUS_NO_USER, 221 | KSMBD_TREE_CONN_STATUS_INVALID_USER, 222 | KSMBD_TREE_CONN_STATUS_HOST_DENIED = 5, 223 | KSMBD_TREE_CONN_STATUS_CONN_EXIST, 224 | KSMBD_TREE_CONN_STATUS_TOO_MANY_CONNS, 225 | KSMBD_TREE_CONN_STATUS_TOO_MANY_SESSIONS, 226 | KSMBD_TREE_CONN_STATUS_ERROR, 227 | }; 228 | 229 | /* 230 | * User config flags. 231 | */ 232 | #define KSMBD_USER_FLAG_INVALID (0) 233 | #define KSMBD_USER_FLAG_OK (1 << 0) 234 | #define KSMBD_USER_FLAG_BAD_PASSWORD (1 << 1) 235 | #define KSMBD_USER_FLAG_BAD_UID (1 << 2) 236 | #define KSMBD_USER_FLAG_BAD_USER (1 << 3) 237 | #define KSMBD_USER_FLAG_GUEST_ACCOUNT (1 << 4) 238 | #define KSMBD_USER_FLAG_DELAY_SESSION (1 << 5) 239 | #define KSMBD_USER_FLAG_EXTENSION (1 << 6) 240 | 241 | /* 242 | * Share config flags. 243 | */ 244 | #define KSMBD_SHARE_FLAG_INVALID (0) 245 | #define KSMBD_SHARE_FLAG_AVAILABLE (1 << 0) 246 | #define KSMBD_SHARE_FLAG_BROWSEABLE (1 << 1) 247 | #define KSMBD_SHARE_FLAG_WRITEABLE (1 << 2) 248 | #define KSMBD_SHARE_FLAG_READONLY (1 << 3) 249 | #define KSMBD_SHARE_FLAG_GUEST_OK (1 << 4) 250 | #define KSMBD_SHARE_FLAG_GUEST_ONLY (1 << 5) 251 | #define KSMBD_SHARE_FLAG_STORE_DOS_ATTRS (1 << 6) 252 | #define KSMBD_SHARE_FLAG_OPLOCKS (1 << 7) 253 | #define KSMBD_SHARE_FLAG_PIPE (1 << 8) 254 | #define KSMBD_SHARE_FLAG_HIDE_DOT_FILES (1 << 9) 255 | #define KSMBD_SHARE_FLAG_INHERIT_OWNER (1 << 10) 256 | #define KSMBD_SHARE_FLAG_STREAMS (1 << 11) 257 | #define KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS (1 << 12) 258 | #define KSMBD_SHARE_FLAG_ACL_XATTR (1 << 13) 259 | #define KSMBD_SHARE_FLAG_UPDATE (1 << 14) 260 | #define KSMBD_SHARE_FLAG_CROSSMNT (1 << 15) 261 | 262 | /* 263 | * Tree connect request flags. 264 | */ 265 | #define KSMBD_TREE_CONN_FLAG_REQUEST_SMB1 (0) 266 | #define KSMBD_TREE_CONN_FLAG_REQUEST_IPV6 (1 << 0) 267 | #define KSMBD_TREE_CONN_FLAG_REQUEST_SMB2 (1 << 1) 268 | 269 | /* 270 | * Tree connect flags. 271 | */ 272 | #define KSMBD_TREE_CONN_FLAG_GUEST_ACCOUNT (1 << 0) 273 | #define KSMBD_TREE_CONN_FLAG_READ_ONLY (1 << 1) 274 | #define KSMBD_TREE_CONN_FLAG_WRITABLE (1 << 2) 275 | #define KSMBD_TREE_CONN_FLAG_ADMIN_ACCOUNT (1 << 3) 276 | #define KSMBD_TREE_CONN_FLAG_UPDATE (1 << 4) 277 | 278 | /* 279 | * RPC over IPC. 280 | */ 281 | #define KSMBD_RPC_METHOD_RETURN (1 << 0) 282 | #define KSMBD_RPC_SRVSVC_METHOD_INVOKE (1 << 1) 283 | #define KSMBD_RPC_SRVSVC_METHOD_RETURN ((1 << 1) | KSMBD_RPC_METHOD_RETURN) 284 | #define KSMBD_RPC_WKSSVC_METHOD_INVOKE (1 << 2) 285 | #define KSMBD_RPC_WKSSVC_METHOD_RETURN ((1 << 2) | KSMBD_RPC_METHOD_RETURN) 286 | #define KSMBD_RPC_IOCTL_METHOD ((1 << 3) | KSMBD_RPC_METHOD_RETURN) 287 | #define KSMBD_RPC_OPEN_METHOD (1 << 4) 288 | #define KSMBD_RPC_WRITE_METHOD (1 << 5) 289 | #define KSMBD_RPC_READ_METHOD ((1 << 6) | KSMBD_RPC_METHOD_RETURN) 290 | #define KSMBD_RPC_CLOSE_METHOD (1 << 7) 291 | #define KSMBD_RPC_RAP_METHOD ((1 << 8) | KSMBD_RPC_METHOD_RETURN) 292 | #define KSMBD_RPC_RESTRICTED_CONTEXT (1 << 9) 293 | #define KSMBD_RPC_SAMR_METHOD_INVOKE (1 << 10) 294 | #define KSMBD_RPC_SAMR_METHOD_RETURN ((1 << 10) | KSMBD_RPC_METHOD_RETURN) 295 | #define KSMBD_RPC_LSARPC_METHOD_INVOKE (1 << 11) 296 | #define KSMBD_RPC_LSARPC_METHOD_RETURN ((1 << 11) | KSMBD_RPC_METHOD_RETURN) 297 | 298 | #define KSMBD_RPC_OK 0 299 | #define KSMBD_RPC_EBAD_FUNC 0x00000001 300 | #define KSMBD_RPC_EACCESS_DENIED 0x00000005 301 | #define KSMBD_RPC_EBAD_FID 0x00000006 302 | #define KSMBD_RPC_ENOMEM 0x00000008 303 | #define KSMBD_RPC_EBAD_DATA 0x0000000D 304 | #define KSMBD_RPC_ENOTIMPLEMENTED 0x00000040 305 | #define KSMBD_RPC_EINVALID_PARAMETER 0x00000057 306 | #define KSMBD_RPC_EMORE_DATA 0x000000EA 307 | #define KSMBD_RPC_EINVALID_LEVEL 0x0000007C 308 | #define KSMBD_RPC_SOME_NOT_MAPPED 0x00000107 309 | 310 | #define KSMBD_CONFIG_OPT_DISABLED 0 311 | #define KSMBD_CONFIG_OPT_ENABLED 1 312 | #define KSMBD_CONFIG_OPT_AUTO 2 313 | #define KSMBD_CONFIG_OPT_MANDATORY 3 314 | 315 | #endif /* _LINUX_KSMBD_SERVER_H */ 316 | -------------------------------------------------------------------------------- /mountd/worker.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * Copyright (C) 2018 Samsung Electronics Co., Ltd. 4 | * 5 | * linux-cifsd-devel@lists.sourceforge.net 6 | */ 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #define MAX_WORKER_THREADS 4 23 | static GThreadPool *pool; 24 | 25 | #define VALID_IPC_MSG(m, t) \ 26 | ({ \ 27 | int ret = 1; \ 28 | if (((m)->sz != sizeof(t))) { \ 29 | pr_err("Bad message: %s\n", __func__); \ 30 | ret = 0; \ 31 | } \ 32 | ret; \ 33 | }) 34 | 35 | static int login_request(struct ksmbd_ipc_msg *msg) 36 | { 37 | struct ksmbd_login_request *req; 38 | struct ksmbd_login_response *resp; 39 | struct ksmbd_ipc_msg *resp_msg; 40 | 41 | resp_msg = ipc_msg_alloc(sizeof(*resp)); 42 | if (!resp_msg) 43 | goto out; 44 | 45 | req = KSMBD_IPC_MSG_PAYLOAD(msg); 46 | resp = KSMBD_IPC_MSG_PAYLOAD(resp_msg); 47 | 48 | resp->status = KSMBD_USER_FLAG_INVALID; 49 | if (VALID_IPC_MSG(msg, struct ksmbd_login_request)) 50 | usm_handle_login_request(req, resp); 51 | 52 | resp_msg->type = KSMBD_EVENT_LOGIN_RESPONSE; 53 | resp->handle = req->handle; 54 | 55 | ipc_msg_send(resp_msg); 56 | out: 57 | ipc_msg_free(resp_msg); 58 | return 0; 59 | } 60 | 61 | static int login_response_payload_sz(char *account) 62 | { 63 | int payload_sz; 64 | struct ksmbd_user *user; 65 | 66 | if (account[0] == '\0') 67 | return 0; 68 | 69 | user = usm_lookup_user(account); 70 | if (!user) 71 | return 0; 72 | 73 | payload_sz = sizeof(gid_t) * user->ngroups; 74 | 75 | put_ksmbd_user(user); 76 | return payload_sz; 77 | } 78 | 79 | static int login_request_ext(struct ksmbd_ipc_msg *msg) 80 | { 81 | struct ksmbd_login_request *req; 82 | struct ksmbd_login_response_ext *resp; 83 | struct ksmbd_ipc_msg *resp_msg; 84 | int payload_sz; 85 | 86 | req = KSMBD_IPC_MSG_PAYLOAD(msg); 87 | 88 | payload_sz = login_response_payload_sz(req->account); 89 | resp_msg = ipc_msg_alloc(sizeof(*resp) + payload_sz); 90 | if (!resp_msg) 91 | goto out; 92 | 93 | resp = KSMBD_IPC_MSG_PAYLOAD(resp_msg); 94 | 95 | if (VALID_IPC_MSG(msg, struct ksmbd_login_request)) 96 | usm_handle_login_request_ext(req, resp); 97 | 98 | resp_msg->type = KSMBD_EVENT_LOGIN_RESPONSE_EXT; 99 | resp->handle = req->handle; 100 | 101 | ipc_msg_send(resp_msg); 102 | out: 103 | ipc_msg_free(resp_msg); 104 | return 0; 105 | } 106 | 107 | static int spnego_authen_request(struct ksmbd_ipc_msg *msg) 108 | { 109 | struct ksmbd_spnego_authen_request *req; 110 | struct ksmbd_spnego_authen_response *resp; 111 | struct ksmbd_ipc_msg *resp_msg = NULL; 112 | struct ksmbd_spnego_auth_out auth_out; 113 | struct ksmbd_login_request login_req; 114 | int retval = 0; 115 | 116 | req = KSMBD_IPC_MSG_PAYLOAD(msg); 117 | resp_msg = ipc_msg_alloc(sizeof(*resp)); 118 | if (!resp_msg) 119 | return -ENOMEM; 120 | resp_msg->type = KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE; 121 | resp = KSMBD_IPC_MSG_PAYLOAD(resp_msg); 122 | resp->handle = req->handle; 123 | resp->login_response.status = KSMBD_USER_FLAG_INVALID; 124 | 125 | if (msg->sz <= sizeof(struct ksmbd_spnego_authen_request)) { 126 | retval = -EINVAL; 127 | goto out; 128 | } 129 | 130 | /* Authentication */ 131 | if (spnego_handle_authen_request(req, &auth_out) != 0) { 132 | retval = -EPERM; 133 | goto out; 134 | } 135 | 136 | ipc_msg_free(resp_msg); 137 | resp_msg = ipc_msg_alloc(sizeof(*resp) + 138 | auth_out.key_len + auth_out.blob_len); 139 | if (!resp_msg) { 140 | retval = -ENOMEM; 141 | goto out_free_auth; 142 | } 143 | 144 | resp_msg->type = KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE; 145 | resp = KSMBD_IPC_MSG_PAYLOAD(resp_msg); 146 | resp->handle = req->handle; 147 | resp->login_response.status = KSMBD_USER_FLAG_INVALID; 148 | 149 | /* login */ 150 | login_req.handle = req->handle; 151 | strncpy(login_req.account, auth_out.user_name, 152 | sizeof(login_req.account)); 153 | usm_handle_login_request(&login_req, &resp->login_response); 154 | if (!(resp->login_response.status & KSMBD_USER_FLAG_OK)) { 155 | pr_info("Unable to login user `%s'\n", login_req.account); 156 | goto out_free_auth; 157 | } 158 | 159 | resp->session_key_len = auth_out.key_len; 160 | memcpy(resp->payload, auth_out.sess_key, auth_out.key_len); 161 | resp->spnego_blob_len = auth_out.blob_len; 162 | memcpy(resp->payload + auth_out.key_len, auth_out.spnego_blob, 163 | auth_out.blob_len); 164 | out_free_auth: 165 | g_free(auth_out.spnego_blob); 166 | g_free(auth_out.sess_key); 167 | g_free(auth_out.user_name); 168 | out: 169 | if (resp_msg) { 170 | ipc_msg_send(resp_msg); 171 | ipc_msg_free(resp_msg); 172 | } 173 | return retval; 174 | } 175 | 176 | static int tree_connect_request(struct ksmbd_ipc_msg *msg) 177 | { 178 | struct ksmbd_tree_connect_request *req; 179 | struct ksmbd_tree_connect_response *resp; 180 | struct ksmbd_ipc_msg *resp_msg; 181 | 182 | resp_msg = ipc_msg_alloc(sizeof(*resp)); 183 | if (!resp_msg) 184 | goto out; 185 | 186 | req = KSMBD_IPC_MSG_PAYLOAD(msg); 187 | resp = KSMBD_IPC_MSG_PAYLOAD(resp_msg); 188 | 189 | resp->status = KSMBD_TREE_CONN_STATUS_ERROR; 190 | resp->connection_flags = 0; 191 | 192 | if (VALID_IPC_MSG(msg, struct ksmbd_tree_connect_request)) 193 | tcm_handle_tree_connect(req, resp); 194 | 195 | resp_msg->type = KSMBD_EVENT_TREE_CONNECT_RESPONSE; 196 | resp->handle = req->handle; 197 | 198 | ipc_msg_send(resp_msg); 199 | out: 200 | ipc_msg_free(resp_msg); 201 | return 0; 202 | } 203 | 204 | static int share_config_request(struct ksmbd_ipc_msg *msg) 205 | { 206 | struct ksmbd_share_config_request *req; 207 | struct ksmbd_share_config_response *resp; 208 | struct ksmbd_share *share = NULL; 209 | struct ksmbd_ipc_msg *resp_msg; 210 | int payload_sz = 0; 211 | 212 | req = KSMBD_IPC_MSG_PAYLOAD(msg); 213 | if (VALID_IPC_MSG(msg, struct ksmbd_share_config_request)) { 214 | share = shm_lookup_share(req->share_name); 215 | if (share) 216 | payload_sz = shm_share_config_payload_size(share); 217 | } 218 | 219 | resp_msg = ipc_msg_alloc(sizeof(*resp) + payload_sz); 220 | if (!resp_msg) 221 | goto out; 222 | 223 | resp = KSMBD_IPC_MSG_PAYLOAD(resp_msg); 224 | resp->payload_sz = payload_sz; 225 | shm_handle_share_config_request(share, resp); 226 | resp_msg->type = KSMBD_EVENT_SHARE_CONFIG_RESPONSE; 227 | resp->handle = req->handle; 228 | 229 | ipc_msg_send(resp_msg); 230 | out: 231 | put_ksmbd_share(share); 232 | ipc_msg_free(resp_msg); 233 | return 0; 234 | } 235 | 236 | static int tree_disconnect_request(struct ksmbd_ipc_msg *msg) 237 | { 238 | struct ksmbd_tree_disconnect_request *req; 239 | 240 | if (!VALID_IPC_MSG(msg, struct ksmbd_tree_disconnect_request)) 241 | return -EINVAL; 242 | 243 | req = KSMBD_IPC_MSG_PAYLOAD(msg); 244 | tcm_handle_tree_disconnect(req->session_id, req->connect_id); 245 | 246 | return 0; 247 | } 248 | 249 | static int logout_request(struct ksmbd_ipc_msg *msg) 250 | { 251 | if (!VALID_IPC_MSG(msg, struct ksmbd_logout_request)) 252 | return -EINVAL; 253 | 254 | return usm_handle_logout_request(KSMBD_IPC_MSG_PAYLOAD(msg)); 255 | } 256 | 257 | static int heartbeat_request(struct ksmbd_ipc_msg *msg) 258 | { 259 | if (!VALID_IPC_MSG(msg, struct ksmbd_heartbeat)) 260 | return -EINVAL; 261 | 262 | pr_debug("HEARTBEAT frame from the server\n"); 263 | return 0; 264 | } 265 | 266 | static int rpc_request(struct ksmbd_ipc_msg *msg) 267 | { 268 | struct ksmbd_rpc_command *req; 269 | struct ksmbd_rpc_command *resp; 270 | struct ksmbd_ipc_msg *resp_msg = NULL; 271 | int ret = -ENOTSUP; 272 | 273 | if (msg->sz < sizeof(struct ksmbd_rpc_command)) 274 | goto out; 275 | 276 | req = KSMBD_IPC_MSG_PAYLOAD(msg); 277 | if (req->flags & KSMBD_RPC_METHOD_RETURN) 278 | resp_msg = ipc_msg_alloc(KSMBD_IPC_MAX_MESSAGE_SIZE - 279 | sizeof(struct ksmbd_rpc_command)); 280 | else 281 | resp_msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command)); 282 | if (!resp_msg) 283 | goto out; 284 | 285 | resp = KSMBD_IPC_MSG_PAYLOAD(resp_msg); 286 | 287 | if ((req->flags & KSMBD_RPC_RAP_METHOD) == KSMBD_RPC_RAP_METHOD) { 288 | pr_err("RAP command is not supported yet %x\n", req->flags); 289 | ret = KSMBD_RPC_ENOTIMPLEMENTED; 290 | } else if (req->flags & KSMBD_RPC_OPEN_METHOD) { 291 | ret = rpc_open_request(req, resp); 292 | } else if (req->flags & KSMBD_RPC_CLOSE_METHOD) { 293 | ret = rpc_close_request(req, resp); 294 | } else if (req->flags & KSMBD_RPC_IOCTL_METHOD) { 295 | ret = rpc_ioctl_request(req, resp, resp_msg->sz); 296 | } else if (req->flags & KSMBD_RPC_WRITE_METHOD) { 297 | ret = rpc_write_request(req, resp); 298 | } else if (req->flags & KSMBD_RPC_READ_METHOD) { 299 | ret = rpc_read_request(req, resp, resp_msg->sz); 300 | } else { 301 | pr_err("Unknown RPC method: %x\n", req->flags); 302 | ret = KSMBD_RPC_ENOTIMPLEMENTED; 303 | } 304 | 305 | resp_msg->type = KSMBD_EVENT_RPC_RESPONSE; 306 | resp->handle = req->handle; 307 | resp->flags = ret; 308 | resp_msg->sz = sizeof(struct ksmbd_rpc_command) + resp->payload_sz; 309 | 310 | ipc_msg_send(resp_msg); 311 | out: 312 | ipc_msg_free(resp_msg); 313 | return 0; 314 | } 315 | 316 | static void worker_pool_fn(gpointer event, gpointer user_data) 317 | { 318 | struct ksmbd_ipc_msg *msg = (struct ksmbd_ipc_msg *)event; 319 | 320 | switch (msg->type) { 321 | case KSMBD_EVENT_LOGIN_REQUEST: 322 | login_request(msg); 323 | break; 324 | 325 | case KSMBD_EVENT_TREE_CONNECT_REQUEST: 326 | tree_connect_request(msg); 327 | break; 328 | 329 | case KSMBD_EVENT_TREE_DISCONNECT_REQUEST: 330 | tree_disconnect_request(msg); 331 | break; 332 | 333 | case KSMBD_EVENT_LOGOUT_REQUEST: 334 | logout_request(msg); 335 | break; 336 | 337 | case KSMBD_EVENT_SHARE_CONFIG_REQUEST: 338 | share_config_request(msg); 339 | break; 340 | 341 | case KSMBD_EVENT_RPC_REQUEST: 342 | rpc_request(msg); 343 | break; 344 | 345 | case KSMBD_EVENT_HEARTBEAT_REQUEST: 346 | heartbeat_request(msg); 347 | break; 348 | 349 | case KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST: 350 | spnego_authen_request(msg); 351 | break; 352 | 353 | case KSMBD_EVENT_LOGIN_REQUEST_EXT: 354 | login_request_ext(msg); 355 | break; 356 | 357 | default: 358 | pr_err("Unknown IPC message type: %d\n", msg->type); 359 | break; 360 | } 361 | 362 | ipc_msg_free(msg); 363 | } 364 | 365 | int wp_ipc_msg_push(struct ksmbd_ipc_msg *msg) 366 | { 367 | return g_thread_pool_push(pool, msg, NULL); 368 | } 369 | 370 | void wp_destroy(void) 371 | { 372 | if (pool) { 373 | g_thread_pool_free(pool, 1, 1); 374 | pool = NULL; 375 | } 376 | } 377 | 378 | void wp_init(void) 379 | { 380 | if (!pool) 381 | pool = g_thread_pool_new( 382 | worker_pool_fn, 383 | NULL, 384 | MAX_WORKER_THREADS, 385 | 0, 386 | NULL); 387 | } 388 | -------------------------------------------------------------------------------- /mountd/mountd.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * Copyright (C) 2018 Samsung Electronics Co., Ltd. 4 | * 5 | * linux-cifsd-devel@lists.sourceforge.net 6 | */ 7 | 8 | #define _GNU_SOURCE 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "ipc.h" 23 | #include "management/share.h" 24 | #include "config_parser.h" 25 | 26 | static void usage(int status) 27 | { 28 | printf( 29 | "Usage: ksmbd.mountd [-v] [-p PORT] [-n[WAY]] [-C CONF] [-P PWDDB]\n"); 30 | 31 | if (status != EXIT_SUCCESS) 32 | printf("Try `ksmbd.mountd --help' for more information.\n"); 33 | else 34 | printf( 35 | "\n" 36 | " -p, --port=PORT bind to PORT instead of TCP port 445\n" 37 | " -n, --nodetach[=WAY] do not detach process from foreground;\n" 38 | " if WAY is 1, become process group leader (default);\n" 39 | " if WAY is 0, detach\n" 40 | " -C, --config=CONF use CONF as configuration file instead of\n" 41 | " `" PATH_SMBCONF "'\n" 42 | " -P, --pwddb=PWDDB use PWDDB as user database instead of\n" 43 | " `" PATH_PWDDB "'\n" 44 | " -v, --verbose be verbose\n" 45 | " -V, --version output version information and exit\n" 46 | " -h, --help display this help and exit\n" 47 | "\n" 48 | "See ksmbd.mountd(8) for more details.\n"); 49 | } 50 | 51 | static struct option opts[] = { 52 | {"port", required_argument, NULL, 'p' }, 53 | {"nodetach", optional_argument, NULL, 'n' }, 54 | {"config", required_argument, NULL, 'C' }, 55 | {"pwddb", required_argument, NULL, 'P' }, 56 | {"verbose", no_argument, NULL, 'v' }, 57 | {"version", no_argument, NULL, 'V' }, 58 | {"help", no_argument, NULL, 'h' }, 59 | {NULL, 0, NULL, 0 } 60 | }; 61 | 62 | #define LIST_FMT_SS "%28s %s" 63 | 64 | static void __list_config_share_cb(struct ksmbd_share *share, int *wfd) 65 | { 66 | dprintf(*wfd, LIST_FMT_SS "\n", share->name, share->comment ?: ""); 67 | } 68 | 69 | static int list_config(int wfd) 70 | { 71 | dprintf(wfd, "\e[1m" LIST_FMT_SS "\e[m" "\n", "Name", "Comment"); 72 | shm_iter_shares((share_cb)__list_config_share_cb, &wfd); 73 | 74 | return kill(global_conf.pid, SIGUSR1) < 0 ? -errno : 0; 75 | } 76 | 77 | static void worker_sa_sigaction(int signo, siginfo_t *siginfo, void *ucontext) 78 | { 79 | switch (signo) { 80 | case SIGIO: 81 | case SIGPIPE: 82 | case SIGCHLD: 83 | return; 84 | case SIGHUP: 85 | ksmbd_health_status |= KSMBD_SHOULD_RELOAD_CONFIG; 86 | return; 87 | case SIGUSR1: 88 | ksmbd_health_status |= KSMBD_SHOULD_LIST_CONFIG; 89 | return; 90 | case SIGINT: 91 | case SIGQUIT: 92 | case SIGTERM: 93 | ksmbd_health_status &= ~KSMBD_HEALTH_RUNNING; 94 | return; 95 | } 96 | 97 | _Exit(128 + signo); 98 | } 99 | 100 | static void worker_init_sa_handler(sigset_t sigset) 101 | { 102 | int signo; 103 | 104 | for (signo = 1; signo < _NSIG; signo++) 105 | if (sigismember(&sigset, signo)) { 106 | struct sigaction act = { 107 | .sa_sigaction = worker_sa_sigaction, 108 | .sa_flags = SA_SIGINFO, 109 | }; 110 | 111 | sigfillset(&act.sa_mask); 112 | sigaction(signo, &act, NULL); 113 | } 114 | } 115 | 116 | static void __splice_pipe(int rfd, int wfd) 117 | { 118 | if (wfd >= 0) { 119 | while (splice(rfd, NULL, wfd, NULL, PIPE_BUF, 0) > 0) 120 | ; 121 | } else { 122 | char buf[PIPE_BUF]; 123 | 124 | while (read(rfd, buf, sizeof(buf)) > 0) 125 | ; 126 | } 127 | } 128 | 129 | static int worker_init_wait(pid_t pid, sigset_t sigset, int rfd) 130 | { 131 | int ret = -ECHILD, wfd = -1; 132 | 133 | if (fcntl(rfd, F_SETFL, fcntl(rfd, F_GETFL) | O_ASYNC) < 0 || 134 | fcntl(rfd, F_SETOWN, global_conf.pid) < 0) { 135 | ret = -errno; 136 | pr_err("Can't control pipe: %m\n"); 137 | return ret; 138 | } 139 | 140 | pr_info("Started worker\n"); 141 | 142 | for (;;) { 143 | siginfo_t siginfo; 144 | 145 | if (sigwaitinfo(&sigset, &siginfo) < 0) 146 | continue; 147 | 148 | if (siginfo.si_signo == SIGIO) { 149 | __splice_pipe(rfd, wfd); 150 | continue; 151 | } 152 | 153 | if (siginfo.si_signo == SIGPIPE) { 154 | if (wfd >= 0) { 155 | close(wfd); 156 | wfd = -1; 157 | } 158 | continue; 159 | } 160 | 161 | if (siginfo.si_signo == SIGCHLD) { 162 | if (siginfo.si_code == CLD_KILLED) 163 | siginfo.si_status += 128; 164 | else if (siginfo.si_code != CLD_EXITED && 165 | siginfo.si_code != CLD_DUMPED) 166 | continue; 167 | if (siginfo.si_status > 128) { 168 | int signo = siginfo.si_status - 128; 169 | 170 | if (!sigismember(&sigset, signo)) 171 | ret = -EIO; 172 | pr_err("Worker " "%s" "killed: %s\n", 173 | ret == -EIO ? "fatally " : "", 174 | strsignal(signo)); 175 | } else if (siginfo.si_status != EXIT_SUCCESS) { 176 | ret = -EIO; 177 | } 178 | __splice_pipe(rfd, wfd); 179 | if (wfd >= 0) 180 | close(wfd); 181 | return ret; 182 | } 183 | 184 | if (siginfo.si_signo == SIGINT || 185 | siginfo.si_signo == SIGQUIT || 186 | siginfo.si_signo == SIGTERM) { 187 | ret = 0; 188 | } else if (siginfo.si_signo == SIGUSR1 && 189 | siginfo.si_pid == pid) { 190 | __splice_pipe(rfd, wfd); 191 | if (wfd >= 0) { 192 | close(wfd); 193 | wfd = -1; 194 | } 195 | continue; 196 | } 197 | 198 | if (kill(pid, siginfo.si_signo) < 0) 199 | continue; 200 | 201 | if (siginfo.si_signo == SIGUSR1) { 202 | g_autofree char *fifo_path = 203 | g_strdup_printf("%s.%d", 204 | PATH_FIFO, 205 | siginfo.si_pid); 206 | 207 | if (wfd >= 0) 208 | continue; 209 | 210 | wfd = open(fifo_path, O_WRONLY | O_NONBLOCK); 211 | if (wfd < 0) 212 | pr_err("Can't open `%s': %m\n", fifo_path); 213 | } 214 | } 215 | } 216 | 217 | static int worker_init(void) 218 | { 219 | sigset_t sigset; 220 | pid_t pid; 221 | int fds[2], ret; 222 | 223 | sigemptyset(&sigset); 224 | sigaddset(&sigset, SIGIO); 225 | sigaddset(&sigset, SIGPIPE); 226 | sigaddset(&sigset, SIGCHLD); 227 | sigaddset(&sigset, SIGHUP); 228 | sigaddset(&sigset, SIGUSR1); 229 | sigaddset(&sigset, SIGINT); 230 | sigaddset(&sigset, SIGQUIT); 231 | sigaddset(&sigset, SIGTERM); 232 | sigaddset(&sigset, SIGABRT); 233 | pthread_sigmask(SIG_BLOCK, &sigset, NULL); 234 | 235 | if (pipe2(fds, O_NONBLOCK) < 0) { 236 | ret = -errno; 237 | pr_err("Can't create pipe: %m\n"); 238 | return ret; 239 | } 240 | 241 | pid = fork(); 242 | if (pid < 0) { 243 | ret = -errno; 244 | pr_err("Can't fork worker: %m\n"); 245 | close(fds[1]); 246 | close(fds[0]); 247 | return ret; 248 | } 249 | if (pid > 0) { 250 | close(fds[1]); 251 | ret = worker_init_wait(pid, sigset, fds[0]); 252 | close(fds[0]); 253 | return ret; 254 | } 255 | 256 | close(fds[0]); 257 | worker_init_sa_handler(sigset); 258 | 259 | ret = load_config(global_conf.pwddb, global_conf.smbconf); 260 | if (ret) 261 | goto out; 262 | 263 | for (;;) { 264 | pthread_sigmask(SIG_UNBLOCK, &sigset, NULL); 265 | 266 | ret = ipc_process_event(); 267 | 268 | pthread_sigmask(SIG_BLOCK, &sigset, NULL); 269 | 270 | if (ret || !(ksmbd_health_status & KSMBD_HEALTH_RUNNING)) 271 | goto out; 272 | 273 | if (ksmbd_health_status & KSMBD_SHOULD_RELOAD_CONFIG) { 274 | ret = load_config(global_conf.pwddb, 275 | global_conf.smbconf); 276 | if (!ret) { 277 | pr_info("Reloaded config\n"); 278 | ksmbd_health_status &= 279 | ~KSMBD_SHOULD_RELOAD_CONFIG; 280 | } 281 | } 282 | 283 | if (ksmbd_health_status & KSMBD_SHOULD_LIST_CONFIG) { 284 | ret = list_config(fds[1]); 285 | if (!ret) { 286 | pr_info("Listed config\n"); 287 | ksmbd_health_status &= 288 | ~KSMBD_SHOULD_LIST_CONFIG; 289 | } 290 | } 291 | } 292 | 293 | out: 294 | close(fds[1]); 295 | remove_config(); 296 | return ret; 297 | } 298 | 299 | static int manager_init_wait(sigset_t sigset) 300 | { 301 | pr_info("Started manager\n"); 302 | 303 | for (;;) { 304 | siginfo_t siginfo; 305 | 306 | if (sigwaitinfo(&sigset, &siginfo) < 0) 307 | continue; 308 | 309 | if (siginfo.si_signo == SIGCHLD) { 310 | if (siginfo.si_code != CLD_KILLED && 311 | siginfo.si_code != CLD_EXITED && 312 | siginfo.si_code != CLD_DUMPED) 313 | continue; 314 | pr_err("Can't init manager, check syslog\n"); 315 | return -ECHILD; 316 | } 317 | 318 | if (siginfo.si_signo == SIGUSR1) { 319 | if (siginfo.si_pid != global_conf.pid) 320 | continue; 321 | return 0; 322 | } 323 | } 324 | } 325 | 326 | static int manager_init(int nodetach) 327 | { 328 | int signo; 329 | sigset_t sigset; 330 | int ret; 331 | 332 | for (signo = 1; signo < _NSIG; signo++) { 333 | struct sigaction act = { 334 | .sa_handler = SIG_DFL, 335 | .sa_flags = signo == SIGCHLD ? SA_NOCLDWAIT : 0, 336 | }; 337 | 338 | sigfillset(&act.sa_mask); 339 | sigaction(signo, &act, NULL); 340 | } 341 | 342 | sigemptyset(&sigset); 343 | pthread_sigmask(SIG_SETMASK, &sigset, NULL); 344 | 345 | switch (nodetach) { 346 | case 0: 347 | sigaddset(&sigset, SIGCHLD); 348 | sigaddset(&sigset, SIGUSR1); 349 | pthread_sigmask(SIG_BLOCK, &sigset, NULL); 350 | 351 | global_conf.pid = fork(); 352 | if (global_conf.pid < 0) { 353 | ret = -errno; 354 | pr_err("Can't fork manager: %m\n"); 355 | return ret; 356 | } 357 | if (global_conf.pid > 0) 358 | return manager_init_wait(sigset); 359 | 360 | setsid(); 361 | if (!freopen("/dev/null", "r", stdin) || 362 | !freopen("/dev/null", "w", stdout) || 363 | !freopen("/dev/null", "w", stderr)) { 364 | ret = -errno; 365 | pr_err("Can't redirect stream: %m\n"); 366 | return ret; 367 | } 368 | pr_logger_init(PR_LOGGER_SYSLOG); 369 | 370 | pthread_sigmask(SIG_UNBLOCK, &sigset, NULL); 371 | break; 372 | case 1: 373 | setpgid(0, 0); 374 | } 375 | 376 | ret = cp_parse_lock(); 377 | if (ret) 378 | return ret; 379 | 380 | if (cp_parse_subauth()) 381 | pr_info("Ignored subauth file\n"); 382 | 383 | if (!nodetach) { 384 | pid_t ppid = getppid(); 385 | 386 | if (ppid == 1) 387 | return -ESRCH; 388 | if (kill(ppid, SIGUSR1) < 0) { 389 | ret = -errno; 390 | pr_err("Can't send SIGUSR1 to PID %d: %m\n", ppid); 391 | return ret; 392 | } 393 | } 394 | 395 | for (;;) { 396 | ret = worker_init(); 397 | switch (ret) { 398 | case -ECHILD: 399 | sleep(1); 400 | continue; 401 | default: 402 | pr_info("Terminated\n"); 403 | return ret; 404 | } 405 | } 406 | } 407 | 408 | int mountd_main(int argc, char **argv) 409 | { 410 | int ret = -EINVAL; 411 | int nodetach = 0; 412 | int c; 413 | 414 | while ((c = getopt_long(argc, argv, "p:n::C:P:vVh", opts, NULL)) != EOF) 415 | switch (c) { 416 | case 'p': 417 | global_conf.tcp_port = cp_get_group_kv_long(optarg); 418 | break; 419 | case 'n': 420 | nodetach = !optarg ?: cp_get_group_kv_long(optarg); 421 | break; 422 | case 'C': 423 | g_free(global_conf.smbconf); 424 | global_conf.smbconf = g_strdup(optarg); 425 | break; 426 | case 'P': 427 | g_free(global_conf.pwddb); 428 | global_conf.pwddb = g_strdup(optarg); 429 | break; 430 | case 'v': 431 | set_log_level(PR_DEBUG); 432 | break; 433 | case 'V': 434 | ret = show_version(); 435 | goto out; 436 | case 'h': 437 | ret = 0; 438 | /* Fall through */ 439 | case '?': 440 | default: 441 | usage(ret ? EXIT_FAILURE : EXIT_SUCCESS); 442 | goto out; 443 | } 444 | 445 | if (argc > optind) { 446 | usage(ret ? EXIT_FAILURE : EXIT_SUCCESS); 447 | goto out; 448 | } 449 | 450 | if (!global_conf.smbconf) 451 | global_conf.smbconf = g_strdup(PATH_SMBCONF); 452 | 453 | if (!global_conf.pwddb) 454 | global_conf.pwddb = g_strdup(PATH_PWDDB); 455 | 456 | ret = manager_init(nodetach); 457 | out: 458 | return ret ? EXIT_FAILURE : EXIT_SUCCESS; 459 | } 460 | -------------------------------------------------------------------------------- /tools/management/user.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * Copyright (C) 2018 Samsung Electronics Co., Ltd. 4 | * 5 | * linux-cifsd-devel@lists.sourceforge.net 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "linux/ksmbd_server.h" 16 | #include "management/share.h" 17 | #include "management/user.h" 18 | #include "config_parser.h" 19 | #include "tools.h" 20 | 21 | #define KSMBD_USER_STATE_FREEING 1 22 | 23 | static GHashTable *users_table; 24 | static GRWLock users_table_lock; 25 | 26 | static void kill_ksmbd_user(struct ksmbd_user *user) 27 | { 28 | pr_debug("Kill user `%s' [0x%" PRIXPTR "]\n", 29 | user->name, 30 | (uintptr_t)user); 31 | 32 | g_free(user->name); 33 | g_free(user->pass_b64); 34 | g_free(user->pass); 35 | g_free(user->sgid); 36 | g_rw_lock_clear(&user->update_lock); 37 | g_free(user); 38 | } 39 | 40 | int usm_remove_user(struct ksmbd_user *user) 41 | { 42 | int ret = 0; 43 | 44 | if (user->state != KSMBD_USER_STATE_FREEING) { 45 | g_rw_lock_writer_lock(&users_table_lock); 46 | if (!g_hash_table_remove(users_table, user->name)) 47 | ret = -EINVAL; 48 | g_rw_lock_writer_unlock(&users_table_lock); 49 | } 50 | if (!ret) 51 | kill_ksmbd_user(user); 52 | return ret; 53 | } 54 | 55 | struct ksmbd_user *get_ksmbd_user(struct ksmbd_user *user) 56 | { 57 | g_rw_lock_writer_lock(&user->update_lock); 58 | if (user->ref_count != 0) { 59 | user->ref_count++; 60 | g_rw_lock_writer_unlock(&user->update_lock); 61 | } else { 62 | g_rw_lock_writer_unlock(&user->update_lock); 63 | user = NULL; 64 | } 65 | return user; 66 | } 67 | 68 | void put_ksmbd_user(struct ksmbd_user *user) 69 | { 70 | int drop; 71 | 72 | if (!user) 73 | return; 74 | 75 | g_rw_lock_writer_lock(&user->update_lock); 76 | user->ref_count--; 77 | drop = !user->ref_count; 78 | g_rw_lock_writer_unlock(&user->update_lock); 79 | 80 | if (!drop) 81 | return; 82 | 83 | usm_remove_user(user); 84 | } 85 | 86 | void usm_remove_all_users(void) 87 | { 88 | struct ksmbd_user *user; 89 | GHashTableIter iter; 90 | 91 | g_rw_lock_writer_lock(&users_table_lock); 92 | ghash_for_each_remove(user, users_table, iter) { 93 | user->state = KSMBD_USER_STATE_FREEING; 94 | put_ksmbd_user(user); 95 | } 96 | g_rw_lock_writer_unlock(&users_table_lock); 97 | } 98 | 99 | static struct ksmbd_user *new_ksmbd_user(char *name, char *pwd) 100 | { 101 | struct ksmbd_user *user; 102 | struct passwd *e; 103 | size_t pass_sz; 104 | gid_t *sgid = NULL; 105 | int ngroups = 1, i; 106 | 107 | user = g_try_malloc0(sizeof(struct ksmbd_user)); 108 | if (!user) 109 | return NULL; 110 | 111 | g_rw_lock_init(&user->update_lock); 112 | user->name = name; 113 | user->pass_b64 = pwd; 114 | user->ref_count = 1; 115 | 116 | e = getpwnam(name); 117 | if (!e) { 118 | user->uid = KSMBD_SHARE_INVALID_UID; 119 | user->gid = KSMBD_SHARE_INVALID_GID; 120 | } else { 121 | user->uid = e->pw_uid; 122 | user->gid = e->pw_gid; 123 | } 124 | 125 | user->pass = base64_decode(user->pass_b64, &pass_sz); 126 | user->pass_sz = (int)pass_sz; 127 | 128 | if (!e) 129 | goto out; 130 | 131 | do { 132 | g_free(sgid); 133 | sgid = g_try_malloc0(sizeof(gid_t) * ngroups); 134 | if (!sgid) { 135 | g_free(user); 136 | return NULL; 137 | } 138 | } while (getgrouplist(name, KSMBD_SHARE_INVALID_GID, sgid, &ngroups) < 0); 139 | 140 | for (i = 0; i < ngroups; i++) 141 | if (sgid[i] == KSMBD_SHARE_INVALID_GID) { 142 | memmove(sgid + i, sgid + i + 1, 143 | sizeof(gid_t) * (ngroups - i - 1)); 144 | ngroups--; 145 | } 146 | 147 | user->ngroups = ngroups; 148 | user->sgid = sgid; 149 | 150 | out: 151 | return user; 152 | } 153 | 154 | static void usm_clear_users(void) 155 | { 156 | struct ksmbd_user *user; 157 | GHashTableIter iter; 158 | 159 | ghash_for_each(user, users_table, iter) 160 | kill_ksmbd_user(user); 161 | } 162 | 163 | void usm_destroy(void) 164 | { 165 | if (users_table) { 166 | usm_clear_users(); 167 | g_hash_table_destroy(users_table); 168 | users_table = NULL; 169 | } 170 | } 171 | 172 | void usm_init(void) 173 | { 174 | if (!users_table) 175 | users_table = g_hash_table_new(g_str_hash, g_str_equal); 176 | } 177 | 178 | static struct ksmbd_user *__usm_lookup_user(char *name) 179 | { 180 | return g_hash_table_lookup(users_table, name); 181 | } 182 | 183 | struct ksmbd_user *usm_lookup_user(char *name) 184 | { 185 | struct ksmbd_user *user, *ret; 186 | 187 | if (!name) 188 | return NULL; 189 | 190 | g_rw_lock_reader_lock(&users_table_lock); 191 | user = __usm_lookup_user(name); 192 | if (user) { 193 | ret = get_ksmbd_user(user); 194 | if (!ret) 195 | user = NULL; 196 | } 197 | g_rw_lock_reader_unlock(&users_table_lock); 198 | return user; 199 | } 200 | 201 | int usm_user_name(char *name, char *p) 202 | { 203 | int is_name; 204 | 205 | is_name = p > name; 206 | if (!is_name) { 207 | pr_debug("User name is missing\n"); 208 | goto out; 209 | } 210 | is_name = p - name < KSMBD_REQ_MAX_ACCOUNT_NAME_SZ; 211 | if (!is_name) { 212 | pr_debug("User name exceeds %d bytes\n", 213 | KSMBD_REQ_MAX_ACCOUNT_NAME_SZ - 1); 214 | goto out; 215 | } 216 | is_name = g_utf8_validate(name, p - name, NULL); 217 | if (!is_name) { 218 | pr_debug("User name is not UTF-8\n"); 219 | goto out; 220 | } 221 | for (; name < p; name++) { 222 | is_name = cp_printable(name) && *name != ':'; 223 | if (!is_name) { 224 | pr_debug("User name contains `%c' [0x%.2X]\n", 225 | *name, 226 | (unsigned char)*name); 227 | goto out; 228 | } 229 | } 230 | out: 231 | return is_name; 232 | } 233 | 234 | int usm_add_new_user(char *name, char *pwd) 235 | { 236 | int ret = 0; 237 | struct ksmbd_user *user = new_ksmbd_user(name, pwd); 238 | 239 | if (!user) { 240 | g_free(name); 241 | g_free(pwd); 242 | return -ENOMEM; 243 | } 244 | 245 | g_rw_lock_writer_lock(&users_table_lock); 246 | if (__usm_lookup_user(name)) { 247 | g_rw_lock_writer_unlock(&users_table_lock); 248 | pr_debug("Clashed new user `%s' [0x%" PRIXPTR "]\n", 249 | name, 250 | (uintptr_t)user); 251 | kill_ksmbd_user(user); 252 | return 0; 253 | } 254 | 255 | pr_debug("New user `%s' [0x%" PRIXPTR "]\n", 256 | user->name, 257 | (uintptr_t)user); 258 | if (!g_hash_table_insert(users_table, user->name, user)) { 259 | kill_ksmbd_user(user); 260 | ret = -EINVAL; 261 | } else { 262 | struct group *e; 263 | int i; 264 | 265 | pr_debug("... with UID %u\n", 266 | user->uid); 267 | 268 | e = getgrgid(user->gid); 269 | pr_debug("... with GID %u (`%s')\n", 270 | user->gid, 271 | e ? e->gr_name : ""); 272 | 273 | for (i = 0; i < user->ngroups; i++) { 274 | e = getgrgid(user->sgid[i]); 275 | pr_debug("... with SGID %u (`%s')\n", 276 | user->sgid[i], 277 | e ? e->gr_name : ""); 278 | } 279 | } 280 | g_rw_lock_writer_unlock(&users_table_lock); 281 | return ret; 282 | } 283 | 284 | int usm_add_guest_account(char *name) 285 | { 286 | int ret; 287 | struct ksmbd_user *user; 288 | 289 | ret = usm_add_new_user(g_strdup(name), g_strdup("NULL")); 290 | if (ret) 291 | return ret; 292 | 293 | user = usm_lookup_user(name); 294 | if (!user) { 295 | ret = -EINVAL; 296 | } else { 297 | set_user_flag(user, KSMBD_USER_FLAG_GUEST_ACCOUNT); 298 | put_ksmbd_user(user); 299 | } 300 | return ret; 301 | } 302 | 303 | void usm_iter_users(user_cb cb, void *data) 304 | { 305 | struct ksmbd_user *user; 306 | GHashTableIter iter; 307 | 308 | g_rw_lock_reader_lock(&users_table_lock); 309 | ghash_for_each(user, users_table, iter) 310 | cb(user, data); 311 | g_rw_lock_reader_unlock(&users_table_lock); 312 | } 313 | 314 | void usm_update_user_password(struct ksmbd_user *user, char *pwd) 315 | { 316 | size_t pass_sz; 317 | char *pass_b64 = g_strdup(pwd); 318 | char *pass = base64_decode(pass_b64, &pass_sz); 319 | 320 | pr_debug("New password for user `%s' [0x%" PRIXPTR "]\n", 321 | user->name, 322 | (uintptr_t)user); 323 | g_rw_lock_writer_lock(&user->update_lock); 324 | g_free(user->pass_b64); 325 | g_free(user->pass); 326 | user->pass_b64 = pass_b64; 327 | user->pass = pass; 328 | user->pass_sz = (int)pass_sz; 329 | g_rw_lock_writer_unlock(&user->update_lock); 330 | } 331 | 332 | static int usm_copy_user_passhash(struct ksmbd_user *user, 333 | char *pass, 334 | size_t sz) 335 | { 336 | int ret = -ENOSPC; 337 | 338 | if (test_user_flag(user, KSMBD_USER_FLAG_GUEST_ACCOUNT)) 339 | return 0; 340 | 341 | g_rw_lock_reader_lock(&user->update_lock); 342 | if (sz >= user->pass_sz) { 343 | memcpy(pass, user->pass, user->pass_sz); 344 | ret = user->pass_sz; 345 | } 346 | g_rw_lock_reader_unlock(&user->update_lock); 347 | 348 | return ret; 349 | } 350 | 351 | static int usm_copy_user_account(struct ksmbd_user *user, 352 | char *account, 353 | size_t sz) 354 | { 355 | int account_sz; 356 | 357 | if (test_user_flag(user, KSMBD_USER_FLAG_GUEST_ACCOUNT)) 358 | return 0; 359 | 360 | account_sz = strlen(user->name); 361 | if (sz >= account_sz) { 362 | memcpy(account, user->name, account_sz); 363 | return 0; 364 | } 365 | pr_err("Cannot copy user data, buffer overrun\n"); 366 | return -ENOSPC; 367 | } 368 | 369 | static void __handle_login_request(struct ksmbd_login_response *resp, 370 | struct ksmbd_user *user) 371 | { 372 | int hash_sz; 373 | 374 | resp->gid = user->gid; 375 | resp->uid = user->uid; 376 | resp->status = user->flags; 377 | resp->status |= KSMBD_USER_FLAG_OK; 378 | 379 | if (user->ngroups) 380 | resp->status |= KSMBD_USER_FLAG_EXTENSION; 381 | 382 | hash_sz = usm_copy_user_passhash(user, 383 | resp->hash, 384 | sizeof(resp->hash)); 385 | if (hash_sz < 0) { 386 | resp->status = KSMBD_USER_FLAG_INVALID; 387 | } else { 388 | resp->hash_sz = (unsigned short)hash_sz; 389 | if (usm_copy_user_account(user, 390 | resp->account, 391 | sizeof(resp->account))) 392 | resp->status = KSMBD_USER_FLAG_INVALID; 393 | } 394 | } 395 | 396 | int usm_handle_login_request(struct ksmbd_login_request *req, 397 | struct ksmbd_login_response *resp) 398 | { 399 | struct ksmbd_user *user = NULL; 400 | int null_session = 0; 401 | 402 | if (req->account[0] == '\0') 403 | null_session = 1; 404 | 405 | if (!null_session) 406 | user = usm_lookup_user(req->account); 407 | if (user) { 408 | __handle_login_request(resp, user); 409 | put_ksmbd_user(user); 410 | return 0; 411 | } 412 | 413 | resp->status = KSMBD_USER_FLAG_BAD_USER; 414 | if (!null_session && 415 | global_conf.map_to_guest == KSMBD_CONF_MAP_TO_GUEST_NEVER) 416 | return 0; 417 | 418 | if (null_session || 419 | global_conf.map_to_guest == KSMBD_CONF_MAP_TO_GUEST_BAD_USER) 420 | user = usm_lookup_user(global_conf.guest_account); 421 | 422 | if (!user) 423 | return 0; 424 | 425 | __handle_login_request(resp, user); 426 | put_ksmbd_user(user); 427 | return 0; 428 | } 429 | 430 | int usm_handle_login_request_ext(struct ksmbd_login_request *req, 431 | struct ksmbd_login_response_ext *resp) 432 | { 433 | struct ksmbd_user *user; 434 | 435 | resp->ngroups = 0; 436 | 437 | if (req->account[0] == '\0') 438 | return 0; 439 | 440 | user = usm_lookup_user(req->account); 441 | if (user) { 442 | resp->ngroups = user->ngroups; 443 | memcpy(resp->____payload, user->sgid, 444 | sizeof(gid_t) * user->ngroups); 445 | } 446 | 447 | put_ksmbd_user(user); 448 | return 0; 449 | } 450 | 451 | int usm_handle_logout_request(struct ksmbd_logout_request *req) 452 | { 453 | struct ksmbd_user *user; 454 | 455 | user = usm_lookup_user(req->account); 456 | if (!user) 457 | return -ENOENT; 458 | 459 | if (req->account_flags & KSMBD_USER_FLAG_BAD_PASSWORD) { 460 | if (user->failed_login_count < 10) 461 | user->failed_login_count++; 462 | else 463 | user->flags |= KSMBD_USER_FLAG_DELAY_SESSION; 464 | } else { 465 | user->failed_login_count = 0; 466 | user->flags &= ~KSMBD_USER_FLAG_DELAY_SESSION; 467 | } 468 | 469 | put_ksmbd_user(user); 470 | return 0; 471 | } 472 | --------------------------------------------------------------------------------