Skip to content

Commit cbd0032

Browse files
committed
adde foreground cmd arg; separated user and group cache; ignore permission denied when trying to create home dirs
1 parent c303b4e commit cbd0032

3 files changed

Lines changed: 151 additions & 115 deletions

File tree

src/gitlabapi.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ Error GitLab::fetchGroups(User& user) const {
9797

9898
Error GitLab::fetchGroupByName(const std::string& groupname, Group& group) const {
9999
/** \todo should not hurt to apply url-encoding of the groupname **/
100-
auto fetched = fetch(config, std::format("{}/groups?search={}", config.gitlabapi.baseUrl, groupname));
100+
auto fetched = fetch(config, std::format("{}/groups?search={}&active=true", config.gitlabapi.baseUrl, groupname));
101101
if (!fetched.has_value())
102102
return fetched.error();
103103
auto& json = fetched.value();
@@ -115,7 +115,7 @@ Error GitLab::fetchGroupByName(const std::string& groupname, Group& group) const
115115
}
116116

117117
Error GitLab::fetchGroupByID(GroupID id, Group& group) const {
118-
auto fetched = fetch(config, std::format("{}/groups/{}", config.gitlabapi.baseUrl, id));
118+
auto fetched = fetch(config, std::format("{}/groups/{}?with_projects=false", config.gitlabapi.baseUrl, id));
119119
if (!fetched.has_value())
120120
return fetched.error();
121121
auto& json = fetched.value();

src/gitlabnssd.cpp

Lines changed: 142 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,19 @@ class GitLabDaemonImpl final : public GitLabDaemon::Server {
5252
private:
5353
Config config;
5454
gitlab::GitLab gitlab;
55-
cache::lru_cache<std::string, std::any> cache{20}; // Cache for the most recent 20 calls.
55+
cache::lru_cache<std::string, gitlab::User> usercache{20}; // Cache for the most recent 20 user calls.
56+
cache::lru_cache<std::string, gitlab::Group> groupcache{40}; // Cache for the most recent 40 group calls.
5657
std::map<gitlab::GroupID, gid_t> groupMap;
5758

59+
template <typename V>
60+
cache::lru_cache<std::string, V>& getcache();
61+
5862
template <typename T>
5963
bool findInCache(const std::string& cacheId, T& value) {
64+
auto& cache = getcache<T>();
6065
if (cache.exists(cacheId)) {
6166
spdlog::info("Found in cache");
62-
if (const T* val = std::any_cast<T>(&cache.get(cacheId))) {
67+
if (const T* val = &cache.get(cacheId)) {
6368
value = *val;
6469
return true;
6570
} else {
@@ -99,129 +104,156 @@ class GitLabDaemonImpl final : public GitLabDaemon::Server {
99104
public:
100105
GitLabDaemonImpl(Config config) : config(config), gitlab(this->config), groupMap(resolveGroupMap()) {}
101106

102-
virtual ::kj::Promise<void> getUserByID(GetUserByIDContext context) override {
103-
spdlog::info("getUserByID({})", context.getParams().getId());
104-
auto cacheId = std::format("getUserByID({})", context.getParams().getId());
105-
gitlab::User user;
106-
Error err = Error::Ok;
107-
if (findInCache(cacheId, user) ||
108-
((err = gitlab.fetchUserByID(context.getParams().getId(), user)) == Error::Ok &&
109-
(err = gitlab.fetchGroups(user)) == Error::Ok)) {
110-
spdlog::debug("Found");
111-
cache.put(cacheId, user);
112-
auto output = context.getResults().initUser();
113-
output.setId(user.id);
114-
output.setName(user.name);
115-
output.setUsername(user.username);
116-
output.setState(user.state);
117-
auto groups = output.initGroups(user.groups.size());
118-
for (auto i = 0; i < user.groups.size(); ++i) {
119-
if (decltype(groupMap)::iterator it; (it = groupMap.find(user.groups[i].id)) != groupMap.end()) {
120-
// Group mapped to host group
121-
groups[i].setId(it->second);
122-
groups[i].setName("");
123-
groups[i].setLocal(true);
124-
} else {
125-
// GitLab group
126-
groups[i].setId(user.groups[i].id);
127-
groups[i].setName(user.groups[i].name);
128-
groups[i].setLocal(false);
129-
}
107+
virtual ::kj::Promise<void> getUserByID(GetUserByIDContext context) override;
108+
virtual ::kj::Promise<void> getUserByName(GetUserByNameContext context) override;
109+
virtual ::kj::Promise<void> getSSHKeys(GetSSHKeysContext context) override;
110+
virtual ::kj::Promise<void> getGroupByID(GetGroupByIDContext context) override;
111+
virtual ::kj::Promise<void> getGroupByName(GetGroupByNameContext context) override;
112+
};
113+
114+
template <>
115+
constexpr cache::lru_cache<std::string, gitlab::User>& GitLabDaemonImpl::getcache<gitlab::User>() {
116+
return usercache;
117+
}
118+
template <>
119+
constexpr cache::lru_cache<std::string, gitlab::Group>& GitLabDaemonImpl::getcache<gitlab::Group>() {
120+
return groupcache;
121+
}
122+
123+
::kj::Promise<void> GitLabDaemonImpl::getUserByID(GetUserByIDContext context) {
124+
auto& cache = getcache<gitlab::User>();
125+
spdlog::info("getUserByID({})", context.getParams().getId());
126+
auto cacheId = std::format("getUserByID({})", context.getParams().getId());
127+
gitlab::User user;
128+
Error err = Error::Ok;
129+
if (findInCache(cacheId, user) || ((err = gitlab.fetchUserByID(context.getParams().getId(), user)) == Error::Ok &&
130+
(err = gitlab.fetchGroups(user)) == Error::Ok)) {
131+
spdlog::debug("Found");
132+
cache.put(cacheId, user);
133+
cache.put(std::format("getUserByName({})", user.name), user);
134+
auto output = context.getResults().initUser();
135+
output.setId(user.id);
136+
output.setName(user.name);
137+
output.setUsername(user.username);
138+
output.setState(user.state);
139+
auto groups = output.initGroups(user.groups.size());
140+
for (auto i = 0; i < user.groups.size(); ++i) {
141+
if (decltype(groupMap)::iterator it; (it = groupMap.find(user.groups[i].id)) != groupMap.end()) {
142+
// Group mapped to host group
143+
groups[i].setId(it->second);
144+
groups[i].setName("");
145+
groups[i].setLocal(true);
146+
} else {
147+
// GitLab group
148+
groups[i].setId(user.groups[i].id);
149+
groups[i].setName(user.groups[i].name);
150+
groups[i].setLocal(false);
130151
}
131152
}
132-
context.getResults().setErrcode(static_cast<uint32_t>(err));
133-
return kj::READY_NOW;
134153
}
135-
virtual ::kj::Promise<void> getUserByName(GetUserByNameContext context) override {
136-
spdlog::info("getUserByName({})", context.getParams().getName().cStr());
137-
auto cacheId = std::format("getUserByName({})", context.getParams().getName().cStr());
138-
gitlab::User user;
139-
Error err = Error::Ok;
140-
if (findInCache(cacheId, user) ||
141-
((err = gitlab.fetchUserByUsername(context.getParams().getName().cStr(), user)) == Error::Ok &&
142-
(err = gitlab.fetchGroups(user)) == Error::Ok)) {
143-
spdlog::debug("Found");
144-
cache.put(cacheId, user);
145-
auto output = context.getResults().initUser();
146-
output.setId(user.id);
147-
output.setName(user.name);
148-
output.setUsername(user.username);
149-
output.setState(user.state);
150-
auto groups = output.initGroups(user.groups.size());
151-
for (auto i = 0; i < user.groups.size(); ++i) {
152-
if (decltype(groupMap)::iterator it; (it = groupMap.find(user.groups[i].id)) != groupMap.end()) {
153-
// Group mapped to host group
154-
groups[i].setId(it->second);
155-
groups[i].setName("");
156-
groups[i].setLocal(true);
157-
} else {
158-
// GitLab group
159-
groups[i].setId(user.groups[i].id);
160-
groups[i].setName(user.groups[i].name);
161-
groups[i].setLocal(false);
162-
}
154+
context.getResults().setErrcode(static_cast<uint32_t>(err));
155+
return kj::READY_NOW;
156+
}
157+
::kj::Promise<void> GitLabDaemonImpl::getUserByName(GetUserByNameContext context) {
158+
auto& cache = getcache<gitlab::User>();
159+
spdlog::info("getUserByName({})", context.getParams().getName().cStr());
160+
auto cacheId = std::format("getUserByName({})", context.getParams().getName().cStr());
161+
gitlab::User user;
162+
Error err = Error::Ok;
163+
if (findInCache(cacheId, user) ||
164+
((err = gitlab.fetchUserByUsername(context.getParams().getName().cStr(), user)) == Error::Ok &&
165+
(err = gitlab.fetchGroups(user)) == Error::Ok)) {
166+
spdlog::debug("Found");
167+
cache.put(cacheId, user);
168+
cache.put(std::format("getUserByID({})", user.id), user);
169+
auto output = context.getResults().initUser();
170+
output.setId(user.id);
171+
output.setName(user.name);
172+
output.setUsername(user.username);
173+
output.setState(user.state);
174+
auto groups = output.initGroups(user.groups.size());
175+
for (auto i = 0; i < user.groups.size(); ++i) {
176+
if (decltype(groupMap)::iterator it; (it = groupMap.find(user.groups[i].id)) != groupMap.end()) {
177+
// Group mapped to host group
178+
groups[i].setId(it->second);
179+
groups[i].setName("");
180+
groups[i].setLocal(true);
181+
} else {
182+
// GitLab group
183+
groups[i].setId(user.groups[i].id);
184+
groups[i].setName(user.groups[i].name);
185+
groups[i].setLocal(false);
163186
}
164187
}
165-
context.getResults().setErrcode(static_cast<uint32_t>(err));
166-
return kj::READY_NOW;
167188
}
189+
context.getResults().setErrcode(static_cast<uint32_t>(err));
190+
return kj::READY_NOW;
191+
}
168192

169-
virtual ::kj::Promise<void> getSSHKeys(GetSSHKeysContext context) {
170-
spdlog::info("getSSHKeys({})", context.getParams().getId());
171-
std::vector<std::string> keys;
172-
Error err;
173-
if ((err = gitlab.fetchAuthorizedKeys(context.getParams().getId(), keys)) == Error::Ok) {
174-
spdlog::debug("Found");
175-
// When std::ranges::to is finally implemented by GCC:
176-
// std::string joined = keys | std::views::join | std::ranges::to<std::string>();
177-
std::string joined;
178-
for (auto&& key : keys)
179-
joined += key + "\n";
193+
::kj::Promise<void> GitLabDaemonImpl::getSSHKeys(GetSSHKeysContext context) {
194+
spdlog::info("getSSHKeys({})", context.getParams().getId());
195+
std::vector<std::string> keys;
196+
Error err;
197+
if ((err = gitlab.fetchAuthorizedKeys(context.getParams().getId(), keys)) == Error::Ok) {
198+
spdlog::debug("Found");
199+
// When std::ranges::to is finally implemented by GCC:
200+
// std::string joined = keys | std::views::join | std::ranges::to<std::string>();
201+
std::string joined;
202+
for (auto&& key : keys)
203+
joined += key + "\n";
180204

181-
context.getResults().setKeys(joined);
182-
}
183-
context.getResults().setErrcode(static_cast<uint32_t>(err));
184-
return kj::READY_NOW;
205+
context.getResults().setKeys(joined);
185206
}
207+
context.getResults().setErrcode(static_cast<uint32_t>(err));
208+
return kj::READY_NOW;
209+
}
186210

187-
virtual ::kj::Promise<void> getGroupByID(GetGroupByIDContext context) override {
188-
spdlog::info("getGroupByID({})", context.getParams().getId());
189-
auto cacheId = std::format("getGroupByID({})", context.getParams().getId());
190-
gitlab::Group group;
191-
Error err = Error::Ok;
192-
if (findInCache(cacheId, group) ||
193-
(err = gitlab.fetchGroupByID(context.getParams().getId(), group)) == Error::Ok) {
194-
spdlog::debug("Found");
195-
cache.put(cacheId, group);
196-
auto output = context.getResults().initGroup();
197-
output.setId(group.id);
198-
output.setName(group.name);
199-
}
200-
context.getResults().setErrcode(static_cast<uint32_t>(err));
201-
return kj::READY_NOW;
211+
::kj::Promise<void> GitLabDaemonImpl::getGroupByID(GetGroupByIDContext context) {
212+
auto& cache = getcache<gitlab::Group>();
213+
spdlog::info("getGroupByID({})", context.getParams().getId());
214+
auto cacheId = std::format("getGroupByID({})", context.getParams().getId());
215+
gitlab::Group group;
216+
Error err = Error::Ok;
217+
if (findInCache(cacheId, group) || (err = gitlab.fetchGroupByID(context.getParams().getId(), group)) == Error::Ok) {
218+
spdlog::debug("Found");
219+
cache.put(std::format("getGroupByName({})", group.name), group);
220+
cache.put(cacheId, group);
221+
auto output = context.getResults().initGroup();
222+
output.setId(group.id);
223+
output.setName(group.name);
202224
}
203-
virtual ::kj::Promise<void> getGroupByName(GetGroupByNameContext context) override {
204-
spdlog::info("getGroupByName({})", context.getParams().getName().cStr());
205-
auto cacheId = std::format("getGroupByName({})", context.getParams().getName().cStr());
206-
gitlab::Group group;
207-
Error err = Error::Ok;
208-
if (findInCache(cacheId, group) ||
209-
(err = gitlab.fetchGroupByName(context.getParams().getName().cStr(), group)) == Error::Ok) {
210-
spdlog::debug("Found");
211-
cache.put(cacheId, group);
212-
auto output = context.getResults().initGroup();
213-
output.setId(group.id);
214-
output.setName(group.name);
215-
}
216-
context.getResults().setErrcode(static_cast<uint32_t>(err));
217-
return kj::READY_NOW;
225+
context.getResults().setErrcode(static_cast<uint32_t>(err));
226+
return kj::READY_NOW;
227+
}
228+
::kj::Promise<void> GitLabDaemonImpl::getGroupByName(GetGroupByNameContext context) {
229+
auto& cache = getcache<gitlab::Group>();
230+
spdlog::info("getGroupByName({})", context.getParams().getName().cStr());
231+
auto cacheId = std::format("getGroupByName({})", context.getParams().getName().cStr());
232+
gitlab::Group group;
233+
Error err = Error::Ok;
234+
if (findInCache(cacheId, group) ||
235+
(err = gitlab.fetchGroupByName(context.getParams().getName().cStr(), group)) == Error::Ok) {
236+
spdlog::debug("Found");
237+
cache.put(cacheId, group);
238+
cache.put(std::format("getGroupByID({})", group.id), group);
239+
auto output = context.getResults().initGroup();
240+
output.setId(group.id);
241+
output.setName(group.name);
218242
}
219-
};
243+
context.getResults().setErrcode(static_cast<uint32_t>(err));
244+
return kj::READY_NOW;
245+
}
220246

221247
static auto [promise, fulfiller] = kj::newPromiseAndFulfiller<void>();
222248
int main(int argc, char* argv[]) {
223-
// Daemonize
224-
daemon(0, 0);
249+
bool daemonize = true;
250+
if (argc == 2 && argv[1] == std::string_view{"--foreground"}) {
251+
daemonize = false;
252+
} else if (argc != 1) {
253+
return -1; // Invalid CLI Args
254+
}
255+
if (daemonize)
256+
daemon(0, 0);
225257
{
226258
std::ofstream fstream((std::filesystem::absolute("run") / "gitlabnssd.pid").c_str());
227259
fstream << getpid() << std::endl;

src/nss_interface.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,13 @@ void populatePasswd(passwd& pwd, const User::Reader& user, std::span<char> buffe
7070
pwd.pw_dir = buffer.data() + stream.tellp();
7171
std::string homedir = config.nss.homesRoot / user.getUsername().cStr();
7272
if (config.nss.createHomedirs && !fs::exists(config.nss.homesRoot / user.getUsername().cStr())) {
73-
fs::create_directories(config.nss.homesRoot / user.getUsername().cStr());
74-
chown(homedir.c_str(), pwd.pw_uid, pwd.pw_gid);
75-
chmod(homedir.c_str(), config.nss.homePerms);
73+
try {
74+
fs::create_directories(config.nss.homesRoot / user.getUsername().cStr());
75+
chown(homedir.c_str(), pwd.pw_uid, pwd.pw_gid);
76+
chmod(homedir.c_str(), config.nss.homePerms);
77+
} catch (fs::filesystem_error& e) {
78+
/** Ignore permission denied **/
79+
}
7680
}
7781
stream << homedir << '\0';
7882
}

0 commit comments

Comments
 (0)