Loading include/sharedd/api.h +4 −1 Changes for include/sharedd/api.h: 4 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -58,7 +58,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * address:port or [IPv6]:port to listen on). * * Status: smb_state / nfs_state / iscsi_state (disabled|running|failed), * smb_error / nfs_error / iscsi_error, shares, iscsi_targets. * smb_error / nfs_error / iscsi_error, shares, iscsi_targets; while SMB * runs smb_workgroup and smb_netbios_name, the names ksmbd uses: on a * system joined to an AD domain (adconnect) that domain's NetBIOS name and * the machine account, otherwise the settings' workgroup / netbios_name. * * An iSCSI target (served by the kernel's LIO), in replies and as * arguments: Loading src/main.cpp +14 −0 Changes for src/main.cpp: 14 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -166,6 +166,7 @@ private: Mdns _mdns{_cfg}; std::string _smbError, _nfsError, _iscsiError; time_t _nextIscsiRetry = 0; time_t _nextJoinCheck = 0; int _nfsThreads = 0; sysbus::Service _bus; time_t _nextBusTry = 0; Loading Loading @@ -430,6 +431,10 @@ sysbus::Message Daemon::handle(const sysbus::Message &call, const sysbus::Caller sysbus::Message r = sysbus::Message::reply(call); r.add("smb_state", !_cfg.settings.smb ? "disabled" : _smb.running() ? "running" : "failed"); r.add("smb_error", _smbError); if (_smb.running()) { r.add("smb_workgroup", _smb.workgroup()); r.add("smb_netbios_name", _smb.netbios()); } r.add("nfs_state", !_cfg.settings.nfs ? "disabled" : _nfs.running() ? "running" : "failed"); r.add("nfs_error", _nfsError); r.add("shares", (long long)_cfg.shares.size()); Loading Loading @@ -537,7 +542,16 @@ void Daemon::run() { if (_nextIscsiRetry) _iscsi.apply(); _nextIscsiRetry = time(nullptr) + 30; } // joined or left a domain (adconnect): ksmbd takes over its names if (_smb.running() && time(nullptr) >= _nextJoinCheck) { if (_nextJoinCheck && _smb.namesChanged()) { std::cerr << "sharedd: SMB: the domain membership changed, restarting ksmbd" << std::endl; applyServers(true); } _nextJoinCheck = time(nullptr) + 60; } int timeout = _bus.running() && !retry ? -1 : 5000; if (_smb.running() && (timeout < 0 || timeout > 60000)) timeout = 60000; int mdnsDue = _mdns.timeoutMs(); if (mdnsDue >= 0 && (timeout < 0 || mdnsDue < timeout)) timeout = mdnsDue; int r = poll(fds.data(), fds.size(), timeout); Loading src/rpc.cpp +2 −2 Changes for src/rpc.cpp: 2 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -186,7 +186,7 @@ struct ShareEntry { } // namespace std::string RpcPipes::hostName() const { return netbiosName(_cfg.settings); return _netbios.empty() ? netbiosName(_cfg.settings) : _netbios; } uint32_t RpcPipes::open(uint32_t handle, uint32_t method) { Loading Loading @@ -520,7 +520,7 @@ RpcPipes::Bytes RpcPipes::wkstaGetInfo(const Bytes &in) { w.u32(6); w.u32(1); w.str(hostName()); w.str(_cfg.settings.workgroup); w.str(_workgroup.empty() ? _cfg.settings.workgroup : _workgroup); } else { w.ptr(false); err = WerrUnknownLevel; Loading src/rpc.h +7 −0 Changes for src/rpc.h: 7 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -58,6 +58,12 @@ public: explicit RpcPipes(const Config &cfg) : _cfg(cfg) {} // the names ksmbd runs with (a domain member's differ from the settings) void setNames(const std::string &netbios, const std::string &workgroup) { _netbios = netbios; _workgroup = workgroup; } // ksmbd's pipe operations; each returns the status for the kernel // (0 or one of the KSMBD_RPC_E* codes) and fills out where it answers uint32_t open(uint32_t handle, uint32_t method); Loading Loading @@ -91,6 +97,7 @@ private: std::string hostName() const; const Config &_cfg; std::string _netbios, _workgroup; std::map<uint32_t, Pipe> _pipes; }; Loading src/smb.cpp +66 −5 Changes for src/smb.cpp: 66 added lines, 5 removed lines. Original line number Diff line number Diff line Loading @@ -295,6 +295,11 @@ std::string lower(std::string s) { return s; } std::string upper(std::string s) { for (char &c : s) c = (char)toupper((unsigned char)c); return s; } int signingOption(const std::string &s) { if (s == "disabled") return 0; if (s == "enabled") return 1; Loading Loading @@ -351,6 +356,44 @@ std::vector<std::string> accountNames(const std::string &account) { return names; } // adconnectd's joined domains (JOINED): the first one's NetBIOS name and // computer name. false if adconnectd couldn't be asked; empty names: joined // to none bool joinedDomain(std::string &workgroup, std::string &netbios) { int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); if (fd < 0) return false; sockaddr_un a{}; a.sun_family = AF_UNIX; snprintf(a.sun_path, sizeof a.sun_path, "%s", SHAREDD_ADCONNECT_SOCKET); struct timeval tv = {10, 0}; setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv); setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv); if (connect(fd, (sockaddr *)&a, sizeof a) != 0) { close(fd); return false; } static const char req[] = "JOINED\n"; std::string reply; bool ok = ::send(fd, req, sizeof req - 1, MSG_NOSIGNAL) == (ssize_t)(sizeof req - 1); char buf[4096]; for (ssize_t n; ok && (n = recv(fd, buf, sizeof buf, 0)) > 0;) reply.append(buf, (size_t)n); close(fd); /* J <NetBIOS domain> <computer>, a line per domain, then END -- an * older adconnectd answers ERR */ if (reply.size() < 4 || reply.compare(reply.size() - 4, 4, "END\n") != 0) return false; workgroup.clear(); netbios.clear(); if (reply.compare(0, 2, "J\t") != 0) return true; std::string line = reply.substr(2, reply.find('\n') - 2); size_t t = line.find('\t'); if (t == std::string::npos) return false; workgroup = upper(line.substr(0, t)); netbios = upper(line.substr(t + 1)); if (workgroup.size() > 15) workgroup.resize(15); if (netbios.size() > 15) netbios.resize(15); return true; } #ifndef SHAREDD_UID_R // passwd entry of an SMB account name (SMB user names are case-insensitive) struct passwd *lookupUser(const std::string &account) { Loading Loading @@ -570,6 +613,22 @@ bool SmbServer::send(int cmd, const void *payload, size_t len, bool ack, std::st return false; } namespace { bool adconnectPresent(); } void SmbServer::names(std::string &workgroup, std::string &netbios, bool *asked) const { bool ok = adconnectPresent() && joinedDomain(workgroup, netbios); if (asked) *asked = ok; if (!ok || workgroup.empty()) workgroup = _cfg.settings.workgroup; if (!ok || netbios.empty()) netbios = netbiosName(_cfg.settings); } bool SmbServer::namesChanged() const { std::string workgroup, netbios; bool asked; names(workgroup, netbios, &asked); return asked && (workgroup != _workgroup || netbios != _netbios); } bool SmbServer::start(std::string &err) { close(); // ksmbd's generic netlink family has no module alias Loading Loading @@ -642,8 +701,10 @@ bool SmbServer::start(std::string &err) { req.signing = signingOption(s.signing); copy(req.min_prot, sizeof(req.min_prot), s.minProtocol); copy(req.max_prot, sizeof(req.max_prot), s.maxProtocol); copy(req.netbios_name, sizeof(req.netbios_name), netbiosName(s)); copy(req.work_group, sizeof(req.work_group), s.workgroup); names(_workgroup, _netbios); _rpc.setNames(_netbios, _workgroup); copy(req.netbios_name, sizeof(req.netbios_name), _netbios); copy(req.work_group, sizeof(req.work_group), _workgroup); copy(req.server_string, sizeof(req.server_string), s.serverString); req.tcp_port = 445; req.ipc_timeout = 0; // no heartbeat watchdog Loading @@ -660,7 +721,9 @@ bool SmbServer::start(std::string &err) { } usleep(500000); } std::cerr << "sharedd: SMB: ksmbd started as " << netbiosName(s) << " in " << s.workgroup << std::endl; std::cerr << "sharedd: SMB: ksmbd started as " << _netbios << " in " << _workgroup << (_workgroup != s.workgroup || _netbios != netbiosName(s) ? " (the joined domain's names)" : "") << std::endl; return true; } Loading Loading @@ -720,8 +783,6 @@ void SmbServer::handle(int cmd, const unsigned char *payload, size_t len) { } } namespace { bool adconnectPresent(); } void SmbServer::login(const unsigned char *payload, size_t len) { if (len < sizeof(LoginRequestMsg)) return; LoginRequestMsg req; Loading Loading
include/sharedd/api.h +4 −1 Changes for include/sharedd/api.h: 4 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -58,7 +58,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * address:port or [IPv6]:port to listen on). * * Status: smb_state / nfs_state / iscsi_state (disabled|running|failed), * smb_error / nfs_error / iscsi_error, shares, iscsi_targets. * smb_error / nfs_error / iscsi_error, shares, iscsi_targets; while SMB * runs smb_workgroup and smb_netbios_name, the names ksmbd uses: on a * system joined to an AD domain (adconnect) that domain's NetBIOS name and * the machine account, otherwise the settings' workgroup / netbios_name. * * An iSCSI target (served by the kernel's LIO), in replies and as * arguments: Loading
src/main.cpp +14 −0 Changes for src/main.cpp: 14 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -166,6 +166,7 @@ private: Mdns _mdns{_cfg}; std::string _smbError, _nfsError, _iscsiError; time_t _nextIscsiRetry = 0; time_t _nextJoinCheck = 0; int _nfsThreads = 0; sysbus::Service _bus; time_t _nextBusTry = 0; Loading Loading @@ -430,6 +431,10 @@ sysbus::Message Daemon::handle(const sysbus::Message &call, const sysbus::Caller sysbus::Message r = sysbus::Message::reply(call); r.add("smb_state", !_cfg.settings.smb ? "disabled" : _smb.running() ? "running" : "failed"); r.add("smb_error", _smbError); if (_smb.running()) { r.add("smb_workgroup", _smb.workgroup()); r.add("smb_netbios_name", _smb.netbios()); } r.add("nfs_state", !_cfg.settings.nfs ? "disabled" : _nfs.running() ? "running" : "failed"); r.add("nfs_error", _nfsError); r.add("shares", (long long)_cfg.shares.size()); Loading Loading @@ -537,7 +542,16 @@ void Daemon::run() { if (_nextIscsiRetry) _iscsi.apply(); _nextIscsiRetry = time(nullptr) + 30; } // joined or left a domain (adconnect): ksmbd takes over its names if (_smb.running() && time(nullptr) >= _nextJoinCheck) { if (_nextJoinCheck && _smb.namesChanged()) { std::cerr << "sharedd: SMB: the domain membership changed, restarting ksmbd" << std::endl; applyServers(true); } _nextJoinCheck = time(nullptr) + 60; } int timeout = _bus.running() && !retry ? -1 : 5000; if (_smb.running() && (timeout < 0 || timeout > 60000)) timeout = 60000; int mdnsDue = _mdns.timeoutMs(); if (mdnsDue >= 0 && (timeout < 0 || mdnsDue < timeout)) timeout = mdnsDue; int r = poll(fds.data(), fds.size(), timeout); Loading
src/rpc.cpp +2 −2 Changes for src/rpc.cpp: 2 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -186,7 +186,7 @@ struct ShareEntry { } // namespace std::string RpcPipes::hostName() const { return netbiosName(_cfg.settings); return _netbios.empty() ? netbiosName(_cfg.settings) : _netbios; } uint32_t RpcPipes::open(uint32_t handle, uint32_t method) { Loading Loading @@ -520,7 +520,7 @@ RpcPipes::Bytes RpcPipes::wkstaGetInfo(const Bytes &in) { w.u32(6); w.u32(1); w.str(hostName()); w.str(_cfg.settings.workgroup); w.str(_workgroup.empty() ? _cfg.settings.workgroup : _workgroup); } else { w.ptr(false); err = WerrUnknownLevel; Loading
src/rpc.h +7 −0 Changes for src/rpc.h: 7 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -58,6 +58,12 @@ public: explicit RpcPipes(const Config &cfg) : _cfg(cfg) {} // the names ksmbd runs with (a domain member's differ from the settings) void setNames(const std::string &netbios, const std::string &workgroup) { _netbios = netbios; _workgroup = workgroup; } // ksmbd's pipe operations; each returns the status for the kernel // (0 or one of the KSMBD_RPC_E* codes) and fills out where it answers uint32_t open(uint32_t handle, uint32_t method); Loading Loading @@ -91,6 +97,7 @@ private: std::string hostName() const; const Config &_cfg; std::string _netbios, _workgroup; std::map<uint32_t, Pipe> _pipes; }; Loading
src/smb.cpp +66 −5 Changes for src/smb.cpp: 66 added lines, 5 removed lines. Original line number Diff line number Diff line Loading @@ -295,6 +295,11 @@ std::string lower(std::string s) { return s; } std::string upper(std::string s) { for (char &c : s) c = (char)toupper((unsigned char)c); return s; } int signingOption(const std::string &s) { if (s == "disabled") return 0; if (s == "enabled") return 1; Loading Loading @@ -351,6 +356,44 @@ std::vector<std::string> accountNames(const std::string &account) { return names; } // adconnectd's joined domains (JOINED): the first one's NetBIOS name and // computer name. false if adconnectd couldn't be asked; empty names: joined // to none bool joinedDomain(std::string &workgroup, std::string &netbios) { int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); if (fd < 0) return false; sockaddr_un a{}; a.sun_family = AF_UNIX; snprintf(a.sun_path, sizeof a.sun_path, "%s", SHAREDD_ADCONNECT_SOCKET); struct timeval tv = {10, 0}; setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv); setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv); if (connect(fd, (sockaddr *)&a, sizeof a) != 0) { close(fd); return false; } static const char req[] = "JOINED\n"; std::string reply; bool ok = ::send(fd, req, sizeof req - 1, MSG_NOSIGNAL) == (ssize_t)(sizeof req - 1); char buf[4096]; for (ssize_t n; ok && (n = recv(fd, buf, sizeof buf, 0)) > 0;) reply.append(buf, (size_t)n); close(fd); /* J <NetBIOS domain> <computer>, a line per domain, then END -- an * older adconnectd answers ERR */ if (reply.size() < 4 || reply.compare(reply.size() - 4, 4, "END\n") != 0) return false; workgroup.clear(); netbios.clear(); if (reply.compare(0, 2, "J\t") != 0) return true; std::string line = reply.substr(2, reply.find('\n') - 2); size_t t = line.find('\t'); if (t == std::string::npos) return false; workgroup = upper(line.substr(0, t)); netbios = upper(line.substr(t + 1)); if (workgroup.size() > 15) workgroup.resize(15); if (netbios.size() > 15) netbios.resize(15); return true; } #ifndef SHAREDD_UID_R // passwd entry of an SMB account name (SMB user names are case-insensitive) struct passwd *lookupUser(const std::string &account) { Loading Loading @@ -570,6 +613,22 @@ bool SmbServer::send(int cmd, const void *payload, size_t len, bool ack, std::st return false; } namespace { bool adconnectPresent(); } void SmbServer::names(std::string &workgroup, std::string &netbios, bool *asked) const { bool ok = adconnectPresent() && joinedDomain(workgroup, netbios); if (asked) *asked = ok; if (!ok || workgroup.empty()) workgroup = _cfg.settings.workgroup; if (!ok || netbios.empty()) netbios = netbiosName(_cfg.settings); } bool SmbServer::namesChanged() const { std::string workgroup, netbios; bool asked; names(workgroup, netbios, &asked); return asked && (workgroup != _workgroup || netbios != _netbios); } bool SmbServer::start(std::string &err) { close(); // ksmbd's generic netlink family has no module alias Loading Loading @@ -642,8 +701,10 @@ bool SmbServer::start(std::string &err) { req.signing = signingOption(s.signing); copy(req.min_prot, sizeof(req.min_prot), s.minProtocol); copy(req.max_prot, sizeof(req.max_prot), s.maxProtocol); copy(req.netbios_name, sizeof(req.netbios_name), netbiosName(s)); copy(req.work_group, sizeof(req.work_group), s.workgroup); names(_workgroup, _netbios); _rpc.setNames(_netbios, _workgroup); copy(req.netbios_name, sizeof(req.netbios_name), _netbios); copy(req.work_group, sizeof(req.work_group), _workgroup); copy(req.server_string, sizeof(req.server_string), s.serverString); req.tcp_port = 445; req.ipc_timeout = 0; // no heartbeat watchdog Loading @@ -660,7 +721,9 @@ bool SmbServer::start(std::string &err) { } usleep(500000); } std::cerr << "sharedd: SMB: ksmbd started as " << netbiosName(s) << " in " << s.workgroup << std::endl; std::cerr << "sharedd: SMB: ksmbd started as " << _netbios << " in " << _workgroup << (_workgroup != s.workgroup || _netbios != netbiosName(s) ? " (the joined domain's names)" : "") << std::endl; return true; } Loading Loading @@ -720,8 +783,6 @@ void SmbServer::handle(int cmd, const unsigned char *payload, size_t len) { } } namespace { bool adconnectPresent(); } void SmbServer::login(const unsigned char *payload, size_t len) { if (len < sizeof(LoginRequestMsg)) return; LoginRequestMsg req; Loading