Loading src/smb.cpp +216 −9 Changes for src/smb.cpp: 216 added lines, 9 removed lines. Original line number Diff line number Diff line Loading @@ -84,6 +84,8 @@ enum Event { LoginResponseExt = 17, NtlmAuthenRequest = 18, NtlmAuthenResponse = 19, SidMapRequest = 20, SidMapResponse = 21, }; constexpr size_t AccountSize = 48, HashSize = 18, ShareSize = 64; Loading Loading @@ -226,6 +228,31 @@ struct NtlmAuthenResponseMsg { uint32_t reserved[16]; }; // ksmbd_sid_map_request/response: a user's or group's id <-> its Windows // SID (objectSid, from adconnectd), for the owners and ACL entries of // security descriptors -- any account, logged in or not. Asked only with // GlobalFlagSidMap in the startup request. constexpr uint32_t GlobalFlagSidMap = 1u << 5; constexpr uint32_t SidMapToSid = 0x1; // id -> SID, else SID -> id constexpr uint32_t SidMapGroup = 0x2; // the id is a gid enum SidMapStatus : uint32_t { SidMapOk = 0, SidMapNone = 1, SidMapUnavailable = 2 }; constexpr size_t SidSize = 68; // binary SID: 8 bytes + 15 sub-authorities struct SidMapRequestMsg { uint32_t handle; uint32_t flags; IdR id; // SidMapToSid unsigned char sid[SidSize]; // else uint32_t reserved[16]; }; struct SidMapResponseMsg { uint32_t handle; uint32_t status; // SidMapStatus uint32_t flags; // SidMapGroup: id is a gid IdR id; unsigned char sid[SidSize]; uint32_t reserved[16]; }; // the kernel accepts a response only at exactly its struct's size static_assert(sizeof(StartupRequestMsg) == 744, "ksmbd_startup_request"); static_assert(sizeof(LoginRequestMsg) == 116, "ksmbd_login_request"); Loading @@ -239,6 +266,8 @@ static_assert(sizeof(RpcCommandMsg) == 12, "ksmbd_rpc_command"); static_assert(sizeof(SpnegoAuthenResponseMsg) == 168, "ksmbd_spnego_authen_response"); static_assert(sizeof(NtlmAuthenRequestMsg) == 88, "ksmbd_ntlm_authen_request"); static_assert(sizeof(NtlmAuthenResponseMsg) == 88, "ksmbd_ntlm_authen_response"); static_assert(sizeof(SidMapRequestMsg) == 160, "ksmbd_sid_map_request"); static_assert(sizeof(SidMapResponseMsg) == 164, "ksmbd_sid_map_response"); enum : uint16_t { UserOk = 1 << 0, Loading Loading @@ -491,17 +520,22 @@ std::vector<gid_t> groupsOf(const char *name, gid_t gid) { #endif #ifdef SHAREDD_UID_R // systempp's getgrouplist() for _UID_R_SOURCE programs: the groups of // group.yaml and of every <userdb.h> source -- adconnect's GROUPS, so // nested AD groups too, and without enumerating the domain extern "C" int __uid_r_getgrouplist(const char *user, gid_r_t group, gid_r_t *groups, int *ngroups); // all groups of an account (primary first), UUID and GUID ones too std::vector<gid_r_t> groupsOfR(const Account &a) { std::vector<gid_r_t> groups{a.rgid}; setgrent_id_r(); while (struct group_id_r *gr = getgrent_id_r()) { bool member = false, have = false; for (char **m = gr->gr_mem; m && *m; ++m) member = member || a.name == *m; for (auto &g : groups) have = have || uid_r_eq(&g, &gr->gr_gid); if (member && !have) groups.push_back(gr->gr_gid); } endgrent_id_r(); std::vector<gid_r_t> groups(64); int n = (int)groups.size(); int rc = __uid_r_getgrouplist(a.name.c_str(), a.rgid, groups.data(), &n); if (rc < 0 && n > (int)groups.size()) { groups.resize((size_t)n); rc = __uid_r_getgrouplist(a.name.c_str(), a.rgid, groups.data(), &n); } groups.resize(rc > 0 ? (size_t)rc : 0); if (groups.empty()) groups.push_back(a.rgid); return groups; } Loading Loading @@ -709,6 +743,7 @@ bool SmbServer::start(std::string &err) { req.tcp_port = 445; req.ipc_timeout = 0; // no heartbeat watchdog req.file_max = 10000; // 0 would allow no open files at all req.flags |= GlobalFlagSidMap; // we answer SID mapping requests (sidMap()) subAuth(req.sub_auth); // a reset of a previous instance may still be running: retry a little Loading Loading @@ -779,6 +814,7 @@ void SmbServer::handle(int cmd, const unsigned char *payload, size_t len) { case RpcRequest: rpc(payload, len); break; case SpnegoAuthenRequest: spnego(payload, len); break; case NtlmAuthenRequest: ntlmAuthen(payload, len); break; case SidMapRequest: sidMap(payload, len); break; default: break; // heartbeat, tree disconnect, logout: nothing to answer } } Loading Loading @@ -1160,6 +1196,93 @@ bool ntlmViaAdconnect(const std::string &domain, const std::string &account, con return true; } // one request to adconnectd, its whole answer; false if it couldn't be // asked (not running, no answer within timeout seconds) bool adconnectQuery(const std::string &line, std::string &reply, int timeout) { 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 = {timeout, 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; } std::string req = line + "\n"; bool ok = ::send(fd, req.data(), req.size(), MSG_NOSIGNAL) == (ssize_t)req.size(); reply.clear(); char buf[4096]; ssize_t n = 0; while (ok && (n = recv(fd, buf, sizeof buf, 0)) > 0) reply.append(buf, (size_t)n); close(fd); return ok && n == 0; } // the tab-separated fields of the first record of an adconnectd answer std::vector<std::string> firstRecord(const std::string &reply) { std::vector<std::string> f; std::string line = reply.substr(0, reply.find('\n')); size_t p = 0; for (size_t q; (q = line.find('\t', p)) != std::string::npos; p = q + 1) f.push_back(line.substr(p, q - p)); f.push_back(line.substr(p)); return f; } // a binary SID (revision 1, at most 15 sub-authorities) as S-1-...; "" if malformed std::string sidText(const unsigned char *b, size_t size) { if (size < 8 || b[0] != 1 || b[1] > 15 || size < 8 + 4 * (size_t)b[1]) return std::string(); unsigned long long auth = 0; for (int i = 2; i < 8; i++) auth = auth << 8 | b[i]; std::string s = "S-1-" + std::to_string(auth); for (int i = 0; i < b[1]; i++) { const unsigned char *p = b + 8 + 4 * i; s += "-" + std::to_string((uint32_t)p[0] | (uint32_t)p[1] << 8 | (uint32_t)p[2] << 16 | (uint32_t)p[3] << 24); } return s; } // S-1-... into out[SidSize]; false if malformed bool sidBinary(const std::string &t, unsigned char out[SidSize]) { if (t.compare(0, 4, "S-1-") != 0) return false; std::vector<unsigned long long> parts; for (size_t p = 4;;) { size_t q = t.find('-', p); std::string part = t.substr(p, q == std::string::npos ? std::string::npos : q - p); if (part.empty() || part.size() > 15 || part.find_first_not_of("0123456789") != std::string::npos) return false; parts.push_back(strtoull(part.c_str(), nullptr, 10)); if (q == std::string::npos) break; p = q + 1; } if (parts.size() < 2 || parts.size() > 16 || parts[0] >= 1ULL << 48) return false; memset(out, 0, SidSize); out[0] = 1; out[1] = (unsigned char)(parts.size() - 1); for (int i = 0; i < 6; i++) out[2 + i] = (unsigned char)(parts[0] >> (8 * (5 - i))); for (size_t i = 1; i < parts.size(); i++) { if (parts[i] > 0xffffffffULL) return false; for (int k = 0; k < 4; k++) out[8 + 4 * (i - 1) + k] = (unsigned char)(parts[i] >> (8 * k)); } return true; } // whether acct, found by name, is the account adconnectd has under that // name (the same uid) -- and not a local one of the same name bool sameAsDirectory(const std::string &name, const Account &acct) { std::string reply; if (!adconnectQuery("PWNAM " + name, reply, 10)) return false; std::vector<std::string> f = firstRecord(reply); if (f.size() != 7 || f[0] != "U") return false; #ifdef SHAREDD_UID_R char buf[UID_R_STR_LEN]; return f[2] == uid_r_to_str(&acct.ruid, buf); #else return f[2] == std::to_string(acct.uid); #endif } } // namespace // Kerberos logins (domain members asking for cifs/<this system>): the Loading @@ -1184,6 +1307,12 @@ void SmbServer::spnego(const unsigned char *payload, size_t len) { error = "no such user " + k.name; ok = false; } // the ticket is for the domain's account: it must not land on a local // account that merely has the same name (user.yaml comes first) if (ok && !sameAsDirectory(k.name, acct)) { error = k.name + " is a domain user, but the name is a local account here"; ok = false; } if (ok && ((!acct.idR && acct.uid == 0) || locked(acct.name.c_str()))) { error = acct.name + (locked(acct.name.c_str()) ? ": account locked" : ": root may not log in over SMB"); ok = false; Loading Loading @@ -1259,4 +1388,82 @@ void SmbServer::ntlmAuthen(const unsigned char *payload, size_t len) { send(NtlmAuthenResponse, &resp, sizeof(resp), false); } // ksmbd asks for the SID of an id (a file's owner or group, an ACL entry) // or the id of a SID (an owner or ACE a client sets). adconnectd knows the // domain accounts' objectSids (SIDOF / IDOF); for anything else ksmbd keeps // its own S-1-22 SIDs. SidMapNone: no such account or no objectSid (the // kernel may cache that), SidMapUnavailable: the directory couldn't be // asked (it mustn't). adconnectd's own cache and offline cache apply. void SmbServer::sidMap(const unsigned char *payload, size_t len) { if (len < sizeof(SidMapRequestMsg)) return; SidMapRequestMsg req; memcpy(&req, payload, sizeof(req)); SidMapResponseMsg resp; memset(&resp, 0, sizeof(resp)); resp.handle = req.handle; resp.status = SidMapNone; resp.flags = req.flags & SidMapGroup; std::string line; if (req.flags & SidMapToSid) { #ifdef SHAREDD_UID_R uid_r_t id; memset(&id, 0, sizeof(id)); id.type = req.id.type; memcpy(&id.legacy, req.id.id, id.type == UID_R_LEGACY ? sizeof(id.legacy) : sizeof(req.id.id)); char buf[UID_R_STR_LEN]; std::string text = uid_r_to_str(&id, buf); #else uint32_t legacy; memcpy(&legacy, req.id.id, sizeof(legacy)); std::string text = req.id.type == 1 ? std::to_string(legacy) : std::string(); #endif if (!text.empty()) line = std::string("SIDOF ") + (req.flags & SidMapGroup ? "g " : "u ") + text; resp.id = req.id; } else { std::string text = sidText(req.sid, sizeof(req.sid)); if (!text.empty()) line = "IDOF " + text; memcpy(resp.sid, req.sid, sizeof(resp.sid)); } std::string reply; if (line.empty() || !adconnectPresent()) { // nothing to ask: no such mapping } else if (!adconnectQuery(line, reply, 2)) { resp.status = SidMapUnavailable; // the kernel waits about as long } else if (reply == "END\n") { // no account, or one without an objectSid } else if (reply.compare(0, 4, "ERR ") == 0) { resp.status = SidMapUnavailable; std::cerr << "sharedd: SMB: " << line << ": " << reply.substr(4, reply.find('\n') - 4) << std::endl; } else { std::vector<std::string> f = firstRecord(reply); bool group = f.size() == 4 && f[1] == "g"; bool good = f.size() == 4 && f[0] == "S" && (group || f[1] == "u") && reply.size() >= 4 && reply.compare(reply.size() - 4, 4, "END\n") == 0; if (good && (req.flags & SidMapToSid)) { good = sidBinary(f[3], resp.sid); } else if (good) { #ifdef SHAREDD_UID_R uid_r_t id; good = uid_r_from_str(f[2].c_str(), &id) == 0 && (uid_r_is_legacy(&id) || kernelHasUidR()); if (good) resp.id = toIdR(id); #else char *end; unsigned long v = strtoul(f[2].c_str(), &end, 10); good = !f[2].empty() && !*end && v <= 0xfffffffeUL; if (good) { resp.id.type = 1; uint32_t legacy = (uint32_t)v; memcpy(resp.id.id, &legacy, sizeof(legacy)); } #endif resp.flags = group ? SidMapGroup : 0; } if (good) resp.status = SidMapOk; else std::cerr << "sharedd: SMB: " << line << ": bad answer from adconnectd" << std::endl; } send(SidMapResponse, &resp, sizeof(resp), false); } } // namespace sharedd src/smb.h +1 −0 Changes for src/smb.h: 1 added line, 0 removed lines. Original line number Diff line number Diff line Loading @@ -84,6 +84,7 @@ private: void handle(int cmd, const unsigned char *payload, size_t len); void login(const unsigned char *payload, size_t len); void loginExt(const unsigned char *payload, size_t len); void sidMap(const unsigned char *payload, size_t len); void shareConfig(const unsigned char *payload, size_t len); void treeConnect(const unsigned char *payload, size_t len); void rpc(const unsigned char *payload, size_t len); Loading Loading
src/smb.cpp +216 −9 Changes for src/smb.cpp: 216 added lines, 9 removed lines. Original line number Diff line number Diff line Loading @@ -84,6 +84,8 @@ enum Event { LoginResponseExt = 17, NtlmAuthenRequest = 18, NtlmAuthenResponse = 19, SidMapRequest = 20, SidMapResponse = 21, }; constexpr size_t AccountSize = 48, HashSize = 18, ShareSize = 64; Loading Loading @@ -226,6 +228,31 @@ struct NtlmAuthenResponseMsg { uint32_t reserved[16]; }; // ksmbd_sid_map_request/response: a user's or group's id <-> its Windows // SID (objectSid, from adconnectd), for the owners and ACL entries of // security descriptors -- any account, logged in or not. Asked only with // GlobalFlagSidMap in the startup request. constexpr uint32_t GlobalFlagSidMap = 1u << 5; constexpr uint32_t SidMapToSid = 0x1; // id -> SID, else SID -> id constexpr uint32_t SidMapGroup = 0x2; // the id is a gid enum SidMapStatus : uint32_t { SidMapOk = 0, SidMapNone = 1, SidMapUnavailable = 2 }; constexpr size_t SidSize = 68; // binary SID: 8 bytes + 15 sub-authorities struct SidMapRequestMsg { uint32_t handle; uint32_t flags; IdR id; // SidMapToSid unsigned char sid[SidSize]; // else uint32_t reserved[16]; }; struct SidMapResponseMsg { uint32_t handle; uint32_t status; // SidMapStatus uint32_t flags; // SidMapGroup: id is a gid IdR id; unsigned char sid[SidSize]; uint32_t reserved[16]; }; // the kernel accepts a response only at exactly its struct's size static_assert(sizeof(StartupRequestMsg) == 744, "ksmbd_startup_request"); static_assert(sizeof(LoginRequestMsg) == 116, "ksmbd_login_request"); Loading @@ -239,6 +266,8 @@ static_assert(sizeof(RpcCommandMsg) == 12, "ksmbd_rpc_command"); static_assert(sizeof(SpnegoAuthenResponseMsg) == 168, "ksmbd_spnego_authen_response"); static_assert(sizeof(NtlmAuthenRequestMsg) == 88, "ksmbd_ntlm_authen_request"); static_assert(sizeof(NtlmAuthenResponseMsg) == 88, "ksmbd_ntlm_authen_response"); static_assert(sizeof(SidMapRequestMsg) == 160, "ksmbd_sid_map_request"); static_assert(sizeof(SidMapResponseMsg) == 164, "ksmbd_sid_map_response"); enum : uint16_t { UserOk = 1 << 0, Loading Loading @@ -491,17 +520,22 @@ std::vector<gid_t> groupsOf(const char *name, gid_t gid) { #endif #ifdef SHAREDD_UID_R // systempp's getgrouplist() for _UID_R_SOURCE programs: the groups of // group.yaml and of every <userdb.h> source -- adconnect's GROUPS, so // nested AD groups too, and without enumerating the domain extern "C" int __uid_r_getgrouplist(const char *user, gid_r_t group, gid_r_t *groups, int *ngroups); // all groups of an account (primary first), UUID and GUID ones too std::vector<gid_r_t> groupsOfR(const Account &a) { std::vector<gid_r_t> groups{a.rgid}; setgrent_id_r(); while (struct group_id_r *gr = getgrent_id_r()) { bool member = false, have = false; for (char **m = gr->gr_mem; m && *m; ++m) member = member || a.name == *m; for (auto &g : groups) have = have || uid_r_eq(&g, &gr->gr_gid); if (member && !have) groups.push_back(gr->gr_gid); } endgrent_id_r(); std::vector<gid_r_t> groups(64); int n = (int)groups.size(); int rc = __uid_r_getgrouplist(a.name.c_str(), a.rgid, groups.data(), &n); if (rc < 0 && n > (int)groups.size()) { groups.resize((size_t)n); rc = __uid_r_getgrouplist(a.name.c_str(), a.rgid, groups.data(), &n); } groups.resize(rc > 0 ? (size_t)rc : 0); if (groups.empty()) groups.push_back(a.rgid); return groups; } Loading Loading @@ -709,6 +743,7 @@ bool SmbServer::start(std::string &err) { req.tcp_port = 445; req.ipc_timeout = 0; // no heartbeat watchdog req.file_max = 10000; // 0 would allow no open files at all req.flags |= GlobalFlagSidMap; // we answer SID mapping requests (sidMap()) subAuth(req.sub_auth); // a reset of a previous instance may still be running: retry a little Loading Loading @@ -779,6 +814,7 @@ void SmbServer::handle(int cmd, const unsigned char *payload, size_t len) { case RpcRequest: rpc(payload, len); break; case SpnegoAuthenRequest: spnego(payload, len); break; case NtlmAuthenRequest: ntlmAuthen(payload, len); break; case SidMapRequest: sidMap(payload, len); break; default: break; // heartbeat, tree disconnect, logout: nothing to answer } } Loading Loading @@ -1160,6 +1196,93 @@ bool ntlmViaAdconnect(const std::string &domain, const std::string &account, con return true; } // one request to adconnectd, its whole answer; false if it couldn't be // asked (not running, no answer within timeout seconds) bool adconnectQuery(const std::string &line, std::string &reply, int timeout) { 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 = {timeout, 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; } std::string req = line + "\n"; bool ok = ::send(fd, req.data(), req.size(), MSG_NOSIGNAL) == (ssize_t)req.size(); reply.clear(); char buf[4096]; ssize_t n = 0; while (ok && (n = recv(fd, buf, sizeof buf, 0)) > 0) reply.append(buf, (size_t)n); close(fd); return ok && n == 0; } // the tab-separated fields of the first record of an adconnectd answer std::vector<std::string> firstRecord(const std::string &reply) { std::vector<std::string> f; std::string line = reply.substr(0, reply.find('\n')); size_t p = 0; for (size_t q; (q = line.find('\t', p)) != std::string::npos; p = q + 1) f.push_back(line.substr(p, q - p)); f.push_back(line.substr(p)); return f; } // a binary SID (revision 1, at most 15 sub-authorities) as S-1-...; "" if malformed std::string sidText(const unsigned char *b, size_t size) { if (size < 8 || b[0] != 1 || b[1] > 15 || size < 8 + 4 * (size_t)b[1]) return std::string(); unsigned long long auth = 0; for (int i = 2; i < 8; i++) auth = auth << 8 | b[i]; std::string s = "S-1-" + std::to_string(auth); for (int i = 0; i < b[1]; i++) { const unsigned char *p = b + 8 + 4 * i; s += "-" + std::to_string((uint32_t)p[0] | (uint32_t)p[1] << 8 | (uint32_t)p[2] << 16 | (uint32_t)p[3] << 24); } return s; } // S-1-... into out[SidSize]; false if malformed bool sidBinary(const std::string &t, unsigned char out[SidSize]) { if (t.compare(0, 4, "S-1-") != 0) return false; std::vector<unsigned long long> parts; for (size_t p = 4;;) { size_t q = t.find('-', p); std::string part = t.substr(p, q == std::string::npos ? std::string::npos : q - p); if (part.empty() || part.size() > 15 || part.find_first_not_of("0123456789") != std::string::npos) return false; parts.push_back(strtoull(part.c_str(), nullptr, 10)); if (q == std::string::npos) break; p = q + 1; } if (parts.size() < 2 || parts.size() > 16 || parts[0] >= 1ULL << 48) return false; memset(out, 0, SidSize); out[0] = 1; out[1] = (unsigned char)(parts.size() - 1); for (int i = 0; i < 6; i++) out[2 + i] = (unsigned char)(parts[0] >> (8 * (5 - i))); for (size_t i = 1; i < parts.size(); i++) { if (parts[i] > 0xffffffffULL) return false; for (int k = 0; k < 4; k++) out[8 + 4 * (i - 1) + k] = (unsigned char)(parts[i] >> (8 * k)); } return true; } // whether acct, found by name, is the account adconnectd has under that // name (the same uid) -- and not a local one of the same name bool sameAsDirectory(const std::string &name, const Account &acct) { std::string reply; if (!adconnectQuery("PWNAM " + name, reply, 10)) return false; std::vector<std::string> f = firstRecord(reply); if (f.size() != 7 || f[0] != "U") return false; #ifdef SHAREDD_UID_R char buf[UID_R_STR_LEN]; return f[2] == uid_r_to_str(&acct.ruid, buf); #else return f[2] == std::to_string(acct.uid); #endif } } // namespace // Kerberos logins (domain members asking for cifs/<this system>): the Loading @@ -1184,6 +1307,12 @@ void SmbServer::spnego(const unsigned char *payload, size_t len) { error = "no such user " + k.name; ok = false; } // the ticket is for the domain's account: it must not land on a local // account that merely has the same name (user.yaml comes first) if (ok && !sameAsDirectory(k.name, acct)) { error = k.name + " is a domain user, but the name is a local account here"; ok = false; } if (ok && ((!acct.idR && acct.uid == 0) || locked(acct.name.c_str()))) { error = acct.name + (locked(acct.name.c_str()) ? ": account locked" : ": root may not log in over SMB"); ok = false; Loading Loading @@ -1259,4 +1388,82 @@ void SmbServer::ntlmAuthen(const unsigned char *payload, size_t len) { send(NtlmAuthenResponse, &resp, sizeof(resp), false); } // ksmbd asks for the SID of an id (a file's owner or group, an ACL entry) // or the id of a SID (an owner or ACE a client sets). adconnectd knows the // domain accounts' objectSids (SIDOF / IDOF); for anything else ksmbd keeps // its own S-1-22 SIDs. SidMapNone: no such account or no objectSid (the // kernel may cache that), SidMapUnavailable: the directory couldn't be // asked (it mustn't). adconnectd's own cache and offline cache apply. void SmbServer::sidMap(const unsigned char *payload, size_t len) { if (len < sizeof(SidMapRequestMsg)) return; SidMapRequestMsg req; memcpy(&req, payload, sizeof(req)); SidMapResponseMsg resp; memset(&resp, 0, sizeof(resp)); resp.handle = req.handle; resp.status = SidMapNone; resp.flags = req.flags & SidMapGroup; std::string line; if (req.flags & SidMapToSid) { #ifdef SHAREDD_UID_R uid_r_t id; memset(&id, 0, sizeof(id)); id.type = req.id.type; memcpy(&id.legacy, req.id.id, id.type == UID_R_LEGACY ? sizeof(id.legacy) : sizeof(req.id.id)); char buf[UID_R_STR_LEN]; std::string text = uid_r_to_str(&id, buf); #else uint32_t legacy; memcpy(&legacy, req.id.id, sizeof(legacy)); std::string text = req.id.type == 1 ? std::to_string(legacy) : std::string(); #endif if (!text.empty()) line = std::string("SIDOF ") + (req.flags & SidMapGroup ? "g " : "u ") + text; resp.id = req.id; } else { std::string text = sidText(req.sid, sizeof(req.sid)); if (!text.empty()) line = "IDOF " + text; memcpy(resp.sid, req.sid, sizeof(resp.sid)); } std::string reply; if (line.empty() || !adconnectPresent()) { // nothing to ask: no such mapping } else if (!adconnectQuery(line, reply, 2)) { resp.status = SidMapUnavailable; // the kernel waits about as long } else if (reply == "END\n") { // no account, or one without an objectSid } else if (reply.compare(0, 4, "ERR ") == 0) { resp.status = SidMapUnavailable; std::cerr << "sharedd: SMB: " << line << ": " << reply.substr(4, reply.find('\n') - 4) << std::endl; } else { std::vector<std::string> f = firstRecord(reply); bool group = f.size() == 4 && f[1] == "g"; bool good = f.size() == 4 && f[0] == "S" && (group || f[1] == "u") && reply.size() >= 4 && reply.compare(reply.size() - 4, 4, "END\n") == 0; if (good && (req.flags & SidMapToSid)) { good = sidBinary(f[3], resp.sid); } else if (good) { #ifdef SHAREDD_UID_R uid_r_t id; good = uid_r_from_str(f[2].c_str(), &id) == 0 && (uid_r_is_legacy(&id) || kernelHasUidR()); if (good) resp.id = toIdR(id); #else char *end; unsigned long v = strtoul(f[2].c_str(), &end, 10); good = !f[2].empty() && !*end && v <= 0xfffffffeUL; if (good) { resp.id.type = 1; uint32_t legacy = (uint32_t)v; memcpy(resp.id.id, &legacy, sizeof(legacy)); } #endif resp.flags = group ? SidMapGroup : 0; } if (good) resp.status = SidMapOk; else std::cerr << "sharedd: SMB: " << line << ": bad answer from adconnectd" << std::endl; } send(SidMapResponse, &resp, sizeof(resp), false); } } // namespace sharedd
src/smb.h +1 −0 Changes for src/smb.h: 1 added line, 0 removed lines. Original line number Diff line number Diff line Loading @@ -84,6 +84,7 @@ private: void handle(int cmd, const unsigned char *payload, size_t len); void login(const unsigned char *payload, size_t len); void loginExt(const unsigned char *payload, size_t len); void sidMap(const unsigned char *payload, size_t len); void shareConfig(const unsigned char *payload, size_t len); void treeConnect(const unsigned char *payload, size_t len); void rpc(const unsigned char *payload, size_t len); Loading