Merge ~kajiya/+git/google-compute-engine-oslogin:update-master-to-20240701.00 into ~ubuntu-core-dev/+git/google-compute-engine-oslogin:ubuntu/master
- Git
- lp:~kajiya/+git/google-compute-engine-oslogin
- update-master-to-20240701.00
- Merge into ubuntu/master
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | e2cd9a8af8b62b90e6f381fe1eca62d7e80ec03b | ||||
Proposed branch: | ~kajiya/+git/google-compute-engine-oslogin:update-master-to-20240701.00 | ||||
Merge into: | ~ubuntu-core-dev/+git/google-compute-engine-oslogin:ubuntu/master | ||||
Diff against target: |
698 lines (+251/-89) 9 files modified
OWNERS (+2/-2) debian/changelog (+6/-0) packaging/google-compute-engine-oslogin.spec (+1/-0) src/Makefile (+49/-25) src/include/oslogin_utils.h (+8/-0) src/oslogin_utils.cc (+98/-62) src/pam/pam_oslogin_admin.cc (+53/-0) src/pam/pam_oslogin_login.cc (+27/-0) test/oslogin_utils_test.cc (+7/-0) |
||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Utkarsh Gupta | Approve | ||
Review via email:
|
Commit message
New upstream version 20240701.00
Description of the change
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Utkarsh Gupta (utkarsh) wrote : | # |
Ah, I debugged and that's what you need:
commit 421ec6034aebb2f
Author: Utkarsh Gupta <email address hidden>
Date: Wed Jul 24 17:19:21 2024 +0900
d/links: Update links w/ respective .so shipped
diff --git a/debian/changelog b/debian/changelog
index 82fd2b8..f16cf4f 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,5 +1,9 @@
google-
+ [ Utkarsh Gupta ]
+ * d/links: Update links w/ respective .so shipped
+
+ [ Chloé 'kajiya' Smith ]
* New upstream version for upstream tag 20240320.00. (LP: #2073166)
-- Chloé 'kajiya' Smith <email address hidden> Mon, 15 Jul 2024 17:56:01 +0100
diff --git a/debian/links b/debian/links
index 12e449f..f5a4762 100644
--- a/debian/links
+++ b/debian/links
@@ -1,2 +1,2 @@
-lib/libnss_
-lib/libnss_
+lib/libnss_
+lib/libnss_
Sponsoring your upload with this now.
Preview Diff
1 | diff --git a/OWNERS b/OWNERS |
2 | index edde10e..59fca61 100644 |
3 | --- a/OWNERS |
4 | +++ b/OWNERS |
5 | @@ -3,14 +3,14 @@ |
6 | |
7 | approvers: |
8 | - a-crate |
9 | + - ajorg |
10 | - bkatyl |
11 | - chaitanyakulkarni28 |
12 | - dorileo |
13 | - drewhli |
14 | - elicriffield |
15 | + - gaughen |
16 | - jjerger |
17 | - karnvadaliya |
18 | - koln67 |
19 | - - quintonamore |
20 | - - vorakl |
21 | - zmarano |
22 | diff --git a/debian/changelog b/debian/changelog |
23 | index 2c83f42..82fd2b8 100644 |
24 | --- a/debian/changelog |
25 | +++ b/debian/changelog |
26 | @@ -1,3 +1,9 @@ |
27 | +google-compute-engine-oslogin (20240701.00-0ubuntu1) oracular; urgency=medium |
28 | + |
29 | + * New upstream version for upstream tag 20240320.00. (LP: #2073166) |
30 | + |
31 | + -- Chloé 'kajiya' Smith <chloe.smith@canonical.com> Mon, 15 Jul 2024 17:56:01 +0100 |
32 | + |
33 | google-compute-engine-oslogin (20231004.00-0ubuntu5) oracular; urgency=medium |
34 | |
35 | * d/p/0002-inherit-cflags.patch: inherit environment's build flags |
36 | diff --git a/packaging/google-compute-engine-oslogin.spec b/packaging/google-compute-engine-oslogin.spec |
37 | index 8f5eac2..5cf6bc6 100644 |
38 | --- a/packaging/google-compute-engine-oslogin.spec |
39 | +++ b/packaging/google-compute-engine-oslogin.spec |
40 | @@ -67,6 +67,7 @@ make install DESTDIR=%{buildroot} LIBDIR=/%{_lib} VERSION=%{version} INSTALL_SEL |
41 | /%{_lib}/libnss_cache_oslogin-%{version}.so |
42 | /%{_lib}/libnss_oslogin.so.2 |
43 | /%{_lib}/libnss_cache_oslogin.so.2 |
44 | +/%{_lib}/security/pam_oslogin_admin.so |
45 | /%{_lib}/security/pam_oslogin_login.so |
46 | /usr/bin/google_authorized_keys |
47 | /usr/bin/google_authorized_keys_sk |
48 | diff --git a/src/Makefile b/src/Makefile |
49 | index a633c7c..4f21719 100644 |
50 | --- a/src/Makefile |
51 | +++ b/src/Makefile |
52 | @@ -21,12 +21,33 @@ CRONDIR = /etc/cron.d |
53 | SYSTEMDDIR = /lib/systemd/system |
54 | PRESETDIR = /lib/systemd/system-preset |
55 | |
56 | +DEST_LIBDIR = $(LIBDIR) |
57 | +DEST_BINDIR = $(BINDIR) |
58 | +DEST_PAMDIR = $(PAMDIR) |
59 | +DEST_MANDIR = $(MANDIR) |
60 | +DEST_SELINUX = /usr/share/selinux/packages |
61 | +DEST_CRONDIR = $(CRONDIR) |
62 | +DEST_SYSTEMDDIR = $(SYSTEMDDIR) |
63 | +DEST_PRESETDIR = $(PRESETDIR) |
64 | + |
65 | +ifneq ($(DESTDIR),) |
66 | +DEST_LIBDIR = $(DESTDIR)/$(LIBDIR) |
67 | +DEST_BINDIR = $(DESTDIR)/$(BINDIR) |
68 | +DEST_PAMDIR = $(DESTDIR)/$(PAMDIR) |
69 | +DEST_MANDIR = $(DESTDIR)/$(MANDIR) |
70 | +DEST_SELINUX = $(DESTDIR)/usr/share/selinux/packages |
71 | +DEST_CRONDIR = $(DESTDIR)/$(CRONDIR) |
72 | +DEST_SYSTEMDDIR = $(DESTDIR)/$(SYSTEMDDIR) |
73 | +DEST_PRESETDIR = $(DESTDIR)/$(PRESETDIR) |
74 | +endif |
75 | + |
76 | NSS_OSLOGIN_SONAME = libnss_oslogin.so.2 |
77 | NSS_CACHE_OSLOGIN_SONAME = libnss_cache_oslogin.so.2 |
78 | |
79 | NSS_OSLOGIN = libnss_oslogin-$(VERSION).so |
80 | NSS_CACHE_OSLOGIN = libnss_cache_oslogin-$(VERSION).so |
81 | |
82 | +PAM_ADMIN = pam_oslogin_admin.so |
83 | PAM_LOGIN = pam_oslogin_login.so |
84 | |
85 | BINARIES = google_oslogin_nss_cache google_authorized_keys google_authorized_keys_sk google_authorized_principals |
86 | @@ -34,7 +55,7 @@ BINARIES = google_oslogin_nss_cache google_authorized_keys google_authorized_key |
87 | .PHONY: all clean install |
88 | .DEFAULT_GOAL := all |
89 | |
90 | -all: $(NSS_OSLOGIN) $(NSS_CACHE_OSLOGIN) $(PAM_LOGIN) $(BINARIES) |
91 | +all: $(NSS_OSLOGIN) $(NSS_CACHE_OSLOGIN) $(PAM_LOGIN) $(PAM_ADMIN) $(BINARIES) |
92 | |
93 | clean: |
94 | rm -f $(BINARIES) |
95 | @@ -52,12 +73,15 @@ $(NSS_CACHE_OSLOGIN): nss/nss_cache_oslogin.o nss/compat/getpwent_r.o oslogin_ut |
96 | |
97 | # PAM modules |
98 | |
99 | -$(PAM_LOGIN): pam/pam_oslogin_login.o oslogin_sshca.o oslogin_utils.o include/oslogin_sshca.h |
100 | +$(PAM_LOGIN): pam/pam_oslogin_login.o oslogin_sshca.o oslogin_utils.o |
101 | + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -shared $^ -o $@ $(PAMLIBS) |
102 | + |
103 | +$(PAM_ADMIN): pam/pam_oslogin_admin.o oslogin_sshca.o oslogin_utils.o |
104 | $(CXX) $(CXXFLAGS) $(CPPFLAGS) -shared $^ -o $@ $(PAMLIBS) |
105 | |
106 | # Utilities. |
107 | |
108 | -google_authorized_principals: authorized_principals/authorized_principals.o oslogin_utils.o oslogin_sshca.o include/oslogin_sshca.h |
109 | +google_authorized_principals: authorized_principals/authorized_principals.o oslogin_utils.o oslogin_sshca.o |
110 | $(CXX) $(CXXFLAGS) $(CPPFLAGS) $^ -o $@ $(LDLIBS) |
111 | |
112 | google_authorized_keys: authorized_keys/authorized_keys.o oslogin_utils.o |
113 | @@ -71,37 +95,37 @@ google_oslogin_nss_cache: cache_refresh/cache_refresh.o oslogin_utils.o |
114 | |
115 | install: all |
116 | # Make dirs |
117 | - install -d $(DESTDIR)$(LIBDIR) |
118 | - install -d $(DESTDIR)$(PAMDIR) |
119 | - install -d $(DESTDIR)$(BINDIR) |
120 | - install -d $(DESTDIR)$(MANDIR)/man8 |
121 | + install -d $(DEST_LIBDIR) |
122 | + install -d $(DEST_PAMDIR) |
123 | + install -d $(DEST_BINDIR) |
124 | + install -d $(DEST_MANDIR)/man8 |
125 | # NSS modules |
126 | - install -m 0644 -t $(DESTDIR)$(LIBDIR) $(NSS_OSLOGIN) $(NSS_CACHE_OSLOGIN) |
127 | - ln -sf $(NSS_OSLOGIN) $(DESTDIR)$(LIBDIR)/$(NSS_OSLOGIN_SONAME) |
128 | - ln -sf $(NSS_CACHE_OSLOGIN) $(DESTDIR)$(LIBDIR)/$(NSS_CACHE_OSLOGIN_SONAME) |
129 | + install -m 0644 -t $(DEST_LIBDIR) $(NSS_OSLOGIN) $(NSS_CACHE_OSLOGIN) |
130 | + ln -sf $(NSS_OSLOGIN) $(DEST_LIBDIR)/$(NSS_OSLOGIN_SONAME) |
131 | + ln -sf $(NSS_CACHE_OSLOGIN) $(DEST_LIBDIR)/$(NSS_CACHE_OSLOGIN_SONAME) |
132 | # PAM modules |
133 | - install -m 0644 -t $(DESTDIR)$(PAMDIR) $(PAM_LOGIN) |
134 | + install -m 0644 -t $(DEST_PAMDIR) $(PAM_LOGIN) $(PAM_ADMIN) |
135 | # Binaries |
136 | - install -m 0755 -t $(DESTDIR)$(BINDIR) $(BINARIES) |
137 | + install -m 0755 -t $(DEST_BINDIR) $(BINARIES) |
138 | # Manpages |
139 | - install -m 0644 -t $(DESTDIR)$(MANDIR)/man8 $(TOPDIR)/man/nss-oslogin.8 $(TOPDIR)/man/nss-cache-oslogin.8 |
140 | - gzip -9f $(DESTDIR)$(MANDIR)/man8/nss-oslogin.8 |
141 | - gzip -9f $(DESTDIR)$(MANDIR)/man8/nss-cache-oslogin.8 |
142 | - ln -sf nss-oslogin.8.gz $(DESTDIR)$(MANDIR)/man8/$(NSS_OSLOGIN_SONAME).8.gz |
143 | - ln -sf nss-cache-oslogin.8.gz $(DESTDIR)$(MANDIR)/man8/$(NSS_CACHE_OSLOGIN_SONAME).8.gz |
144 | + install -m 0644 -t $(DEST_MANDIR)/man8 $(TOPDIR)/man/nss-oslogin.8 $(TOPDIR)/man/nss-cache-oslogin.8 |
145 | + gzip -9f $(DEST_MANDIR)/man8/nss-oslogin.8 |
146 | + gzip -9f $(DEST_MANDIR)/man8/nss-cache-oslogin.8 |
147 | + ln -sf nss-oslogin.8.gz $(DEST_MANDIR)/man8/$(NSS_OSLOGIN_SONAME).8.gz |
148 | + ln -sf nss-cache-oslogin.8.gz $(DEST_MANDIR)/man8/$(NSS_CACHE_OSLOGIN_SONAME).8.gz |
149 | ifdef INSTALL_SELINUX |
150 | # SELinux policy package |
151 | - install -d $(DESTDIR)/usr/share/selinux/packages |
152 | - install -m 0644 -t $(DESTDIR)/usr/share/selinux/packages $(TOPDIR)/selinux/oslogin.pp |
153 | + install -d $(DEST_SELINUX) |
154 | + install -m 0644 -t $(DEST_SELINUX) $(TOPDIR)/selinux/oslogin.pp |
155 | endif |
156 | ifdef INSTALL_CRON |
157 | # Cache refresh cron |
158 | - install -d $(DESTDIR)$(CRONDIR) |
159 | - install -m 0644 $(TOPDIR)/cron.d $(DESTDIR)$(CRONDIR)/google-compute-engine-oslogin |
160 | + install -d $(DEST_CRONDIR) |
161 | + install -m 0644 $(TOPDIR)/cron.d $(DEST_CRONDIR)/google-compute-engine-oslogin |
162 | else |
163 | # Cache refresh systemd timer |
164 | - install -d $(DESTDIR)$(SYSTEMDDIR) |
165 | - install -m 0644 -t $(DESTDIR)$(SYSTEMDDIR) $(TOPDIR)/google-oslogin-cache.timer $(TOPDIR)/google-oslogin-cache.service |
166 | - install -d $(DESTDIR)$(PRESETDIR) |
167 | - install -m 0644 -t $(DESTDIR)$(PRESETDIR) $(TOPDIR)/90-google-compute-engine-oslogin.preset |
168 | + install -d $(DEST_SYSTEMDDIR) |
169 | + install -m 0644 -t $(DEST_SYSTEMDDIR) $(TOPDIR)/google-oslogin-cache.timer $(TOPDIR)/google-oslogin-cache.service |
170 | + install -d $(DEST_PRESETDIR) |
171 | + install -m 0644 -t $(DEST_PRESETDIR) $(TOPDIR)/90-google-compute-engine-oslogin.preset |
172 | endif |
173 | diff --git a/src/include/oslogin_utils.h b/src/include/oslogin_utils.h |
174 | index 368790e..e7c41fe 100644 |
175 | --- a/src/include/oslogin_utils.h |
176 | +++ b/src/include/oslogin_utils.h |
177 | @@ -186,6 +186,9 @@ size_t OnCurlWrite(void* buf, size_t size, size_t nmemb, void* userp); |
178 | bool HttpGet(const string& url, string* response, long* http_code); |
179 | bool HttpPost(const string& url, const string& data, string* response, |
180 | long* http_code); |
181 | +// Based on known MDS status codes returns whether the HTTP request |
182 | +// should be retried or not. |
183 | +bool ShouldRetry(long http_code); |
184 | |
185 | // Returns whether user_name is a valid OsLogin user name. |
186 | bool ValidateUserName(const string& user_name); |
187 | @@ -294,6 +297,11 @@ extern void SysLogErr(const char *fmt, ...); |
188 | |
189 | // AuthoOptions wraps authorization options. |
190 | struct AuthOptions { |
191 | + // admin_policy_required determines if a user is only authorized if admin |
192 | + // policy is available for such a user. i.e. AuthorizeUser() should return |
193 | + // false if adminLogin is not available. |
194 | + bool admin_policy_required; |
195 | + |
196 | // security_key determines if the MDS "/users?..." should use |
197 | // the view=securityKey parameter. |
198 | bool security_key; |
199 | diff --git a/src/oslogin_utils.cc b/src/oslogin_utils.cc |
200 | index f8bbf9c..aad560f 100644 |
201 | --- a/src/oslogin_utils.cc |
202 | +++ b/src/oslogin_utils.cc |
203 | @@ -12,7 +12,7 @@ |
204 | // See the License for the specific language governing permissions and |
205 | // limitations under the License. |
206 | |
207 | -// Requires libcurl4-openssl-dev libjson0 and libjson0-dev |
208 | +// Requires libcurl4-openssl-dev, libjson-c5, and libjson-c-dev |
209 | #include <curl/curl.h> |
210 | #include <errno.h> |
211 | #include <grp.h> |
212 | @@ -48,7 +48,10 @@ |
213 | using std::string; |
214 | |
215 | // Maximum number of retries for HTTP requests. |
216 | -const int kMaxRetries = 1; |
217 | +const int kMaxRetries = 3; |
218 | + |
219 | +// Backoff duration 1 sec between retries. |
220 | +const int kBackoffDuration = 1; |
221 | |
222 | // Regex for validating user names. |
223 | static const char kUserNameRegex[] = "^[a-zA-Z0-9._][a-zA-Z0-9._-]{0,31}$"; |
224 | @@ -189,11 +192,29 @@ bool NssCache::GetNextGroup(BufferManager* buf, struct group* result, int* errno |
225 | return ParseJsonToGroup(cached_passwd, result, buf, errnop); |
226 | } |
227 | |
228 | +// ParseJsonRoot is declared early here, away from the other parsing functions |
229 | +// found later (in the "JSON Parsing" section), so LoadJsonUsersToCache can |
230 | +// take advantage of the improved error handling ParseJsonRoot offers. |
231 | +json_object* ParseJsonRoot(const string& json) { |
232 | + json_object* root = NULL; |
233 | + struct json_tokener* tok = json_tokener_new(); |
234 | + |
235 | + root = json_tokener_parse_ex(tok, json.c_str(), -1); |
236 | + if (root == NULL) { |
237 | + enum json_tokener_error jerr = json_tokener_get_error(tok); |
238 | + string error_message = json_tokener_error_desc(jerr); |
239 | + SysLogErr("Failed to parse root JSON element: \"%s\", from input \"%s\"", |
240 | + error_message, json); |
241 | + } |
242 | + |
243 | + json_tokener_free(tok); |
244 | + return root; |
245 | +} |
246 | + |
247 | bool NssCache::LoadJsonUsersToCache(string response) { |
248 | Reset(); |
249 | |
250 | - json_object* root = NULL; |
251 | - root = json_tokener_parse(response.c_str()); |
252 | + json_object* root = ParseJsonRoot(response); |
253 | if (root == NULL) { |
254 | return false; |
255 | } |
256 | @@ -392,6 +413,22 @@ size_t OnCurlWrite(void* buf, size_t size, size_t nmemb, void* userp) { |
257 | return 0; |
258 | } |
259 | |
260 | +bool ShouldRetry(long http_code) { |
261 | + if (http_code == 200) { |
262 | + // Request returned successfully, no need to retry. |
263 | + return false; |
264 | + } |
265 | + if (http_code == 404) { |
266 | + // Metadata key does not exist, no point of retrying. |
267 | + return false; |
268 | + } |
269 | + if (http_code == 400) { |
270 | + // Request parameters are bad, no point of retrying. |
271 | + return false; |
272 | + } |
273 | + return true; |
274 | +} |
275 | + |
276 | bool HttpDo(const string& url, const string& data, string* response, long* http_code) { |
277 | if (response == NULL || http_code == NULL) { |
278 | return false; |
279 | @@ -410,6 +447,10 @@ bool HttpDo(const string& url, const string& data, string* response, long* http_ |
280 | return false; |
281 | } |
282 | do { |
283 | + // Apply backoff strategy before retrying. |
284 | + if (retry_count > 0) { |
285 | + sleep(kBackoffDuration); |
286 | + } |
287 | response_stream.str(""); |
288 | response_stream.clear(); |
289 | curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); |
290 | @@ -428,7 +469,7 @@ bool HttpDo(const string& url, const string& data, string* response, long* http_ |
291 | return false; |
292 | } |
293 | curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, http_code); |
294 | - } while (retry_count++ < kMaxRetries && *http_code == 500); |
295 | + } while (retry_count++ < kMaxRetries && ShouldRetry(*http_code)); |
296 | curl_slist_free_all(header_list); |
297 | } |
298 | *response = response_stream.str(); |
299 | @@ -506,14 +547,12 @@ bool ValidatePasswd(struct passwd* result, BufferManager* buf, int* errnop) { |
300 | // ----------------- JSON Parsing ----------------- |
301 | |
302 | bool ParseJsonToUsers(const string& json, std::vector<string>* result) { |
303 | - json_object* root = NULL; |
304 | - root = json_tokener_parse(json.c_str()); |
305 | - if (root == NULL) { |
306 | - return false; |
307 | - } |
308 | - |
309 | bool ret = false; |
310 | |
311 | + json_object* root = ParseJsonRoot(json); |
312 | + if (root == NULL) { |
313 | + return ret; |
314 | + } |
315 | json_object* users = NULL; |
316 | if (!json_object_object_get_ex(root, "usernames", &users)) { |
317 | ret = true; // means no users, not invalid. |
318 | @@ -535,19 +574,22 @@ cleanup: |
319 | } |
320 | |
321 | bool ParseJsonToGroups(const string& json, std::vector<Group>* result) { |
322 | - json_object* root = NULL; |
323 | - root = json_tokener_parse(json.c_str()); |
324 | - if (root == NULL) { |
325 | - return false; |
326 | - } |
327 | - |
328 | bool ret = false; |
329 | |
330 | - json_object* groups = NULL; |
331 | + json_object* root = ParseJsonRoot(json); |
332 | + if (root == NULL) { |
333 | + return ret; |
334 | + } |
335 | + json_object* groups; |
336 | + json_type groupType; |
337 | if (!json_object_object_get_ex(root, "posixGroups", &groups)) { |
338 | + SysLogErr("failed to parse POSIX groups from \"%s\"", json); |
339 | goto cleanup; |
340 | } |
341 | - if (json_object_get_type(groups) != json_type_array) { |
342 | + groupType = json_object_get_type(groups); |
343 | + if (groupType != json_type_array) { |
344 | + SysLogErr("parsed unexpected type for field \"posixGroups\"; " |
345 | + "want a list, got %s", groupType); |
346 | goto cleanup; |
347 | } |
348 | for (int idx = 0; idx < (int)json_object_array_length(groups); idx++) { |
349 | @@ -555,11 +597,12 @@ bool ParseJsonToGroups(const string& json, std::vector<Group>* result) { |
350 | |
351 | json_object* gid; |
352 | if (!json_object_object_get_ex(group, "gid", &gid)) { |
353 | + SysLogErr("failed to parse gid from group %s", json_object_get_string(group)); |
354 | goto cleanup; |
355 | } |
356 | - |
357 | json_object* name; |
358 | if (!json_object_object_get_ex(group, "name", &name)) { |
359 | + SysLogErr("failed to parse name from group %s", json_object_get_string(group)); |
360 | goto cleanup; |
361 | } |
362 | |
363 | @@ -589,22 +632,19 @@ cleanup: |
364 | |
365 | bool ParseJsonToGroup(const string& json, struct group* result, BufferManager* |
366 | buf, int* errnop) { |
367 | + bool ret = false; |
368 | *errnop = EINVAL; |
369 | int gr_gid = 65535; |
370 | |
371 | - json_object* group = NULL; |
372 | - group = json_tokener_parse(json.c_str()); |
373 | + json_object* group = ParseJsonRoot(json); |
374 | if (group == NULL) { |
375 | return false; |
376 | } |
377 | |
378 | - bool ret = false; |
379 | - |
380 | json_object* gid; |
381 | if (!json_object_object_get_ex(group, "gid", &gid)) { |
382 | goto cleanup; |
383 | } |
384 | - |
385 | json_object* name; |
386 | if (!json_object_object_get_ex(group, "name", &name)) { |
387 | goto cleanup; |
388 | @@ -631,16 +671,13 @@ cleanup: |
389 | |
390 | std::vector<string> ParseJsonToSshKeys(const string& json) { |
391 | std::vector<string> result; |
392 | - json_object* ssh_public_keys = NULL; |
393 | - |
394 | - json_object* root = NULL; |
395 | - root = json_tokener_parse(json.c_str()); |
396 | + json_object* root = ParseJsonRoot(json); |
397 | if (root == NULL) { |
398 | return result; |
399 | } |
400 | |
401 | // Locate the sshPublicKeys object. |
402 | - json_object* login_profiles = NULL; |
403 | + json_object* login_profiles; |
404 | if (!json_object_object_get_ex(root, "loginProfiles", &login_profiles)) { |
405 | goto cleanup; |
406 | } |
407 | @@ -649,6 +686,7 @@ std::vector<string> ParseJsonToSshKeys(const string& json) { |
408 | } |
409 | login_profiles = json_object_array_get_idx(login_profiles, 0); |
410 | |
411 | + json_object* ssh_public_keys; |
412 | if (!json_object_object_get_ex(login_profiles, "sshPublicKeys", &ssh_public_keys)) { |
413 | goto cleanup; |
414 | } |
415 | @@ -701,16 +739,14 @@ cleanup: |
416 | |
417 | std::vector<string> ParseJsonToSshKeysSk(const string& json) { |
418 | std::vector<string> result; |
419 | - json_object* security_keys = NULL; |
420 | |
421 | - json_object* root = NULL; |
422 | - root = json_tokener_parse(json.c_str()); |
423 | + json_object* root = ParseJsonRoot(json); |
424 | if (root == NULL) { |
425 | return result; |
426 | } |
427 | |
428 | // Locate the securityKeys array. |
429 | - json_object* login_profiles = NULL; |
430 | + json_object* login_profiles; |
431 | if (!json_object_object_get_ex(root, "loginProfiles", &login_profiles)) { |
432 | goto cleanup; |
433 | } |
434 | @@ -720,9 +756,11 @@ std::vector<string> ParseJsonToSshKeysSk(const string& json) { |
435 | |
436 | login_profiles = json_object_array_get_idx(login_profiles, 0); |
437 | |
438 | + json_object* security_keys; |
439 | if (!json_object_object_get_ex(login_profiles, "securityKeys", &security_keys)) { |
440 | goto cleanup; |
441 | } |
442 | + |
443 | if (json_object_get_type(security_keys) != json_type_array) { |
444 | goto cleanup; |
445 | } |
446 | @@ -757,19 +795,18 @@ cleanup: |
447 | |
448 | bool ParseJsonToPasswd(const string& json, struct passwd* result, BufferManager* |
449 | buf, int* errnop) { |
450 | + bool ret = false; |
451 | *errnop = EINVAL; |
452 | json_object* root = NULL; |
453 | json_object* origroot = NULL; |
454 | |
455 | - origroot = root = json_tokener_parse(json.c_str()); |
456 | + origroot = root = ParseJsonRoot(json); |
457 | if (root == NULL) { |
458 | return false; |
459 | } |
460 | |
461 | - bool ret = false; |
462 | - json_object* posix_accounts = NULL; |
463 | - |
464 | - json_object* login_profiles = NULL; |
465 | + json_object* posix_accounts; |
466 | + json_object* login_profiles; |
467 | // If this is called from getpwent_r, loginProfiles won't be in the response. |
468 | if (json_object_object_get_ex(root, "loginProfiles", &login_profiles)) { |
469 | if (json_object_get_type(login_profiles) != json_type_array) { |
470 | @@ -888,17 +925,16 @@ bool AddUsersToGroup(std::vector<string> users, struct group* result, |
471 | } |
472 | |
473 | bool ParseJsonToEmail(const string& json, string* email) { |
474 | - json_object* root = NULL; |
475 | - root = json_tokener_parse(json.c_str()); |
476 | + bool ret = false; |
477 | + |
478 | + json_object* root = ParseJsonRoot(json); |
479 | if (root == NULL) { |
480 | - return false; |
481 | + return ret; |
482 | } |
483 | |
484 | - bool ret = false; |
485 | - json_object* json_email = NULL; |
486 | - |
487 | // Locate the email object. |
488 | - json_object* login_profiles = NULL; |
489 | + json_object* login_profiles; |
490 | + json_object* json_email; |
491 | if (!json_object_object_get_ex(root, "loginProfiles", &login_profiles)) { |
492 | goto cleanup; |
493 | } |
494 | @@ -918,8 +954,7 @@ cleanup: |
495 | } |
496 | |
497 | bool ParseJsonToSuccess(const string& json) { |
498 | - json_object* root = NULL; |
499 | - root = json_tokener_parse(json.c_str()); |
500 | + json_object* root = ParseJsonRoot(json); |
501 | if (root == NULL) { |
502 | return false; |
503 | } |
504 | @@ -934,17 +969,15 @@ bool ParseJsonToSuccess(const string& json) { |
505 | } |
506 | |
507 | bool ParseJsonToKey(const string& json, const string& key, string* response) { |
508 | - json_object* root = NULL; |
509 | - root = json_tokener_parse(json.c_str()); |
510 | + bool ret = false; |
511 | + |
512 | + json_object* root = ParseJsonRoot(json); |
513 | if (root == NULL) { |
514 | - return false; |
515 | + return ret; |
516 | } |
517 | |
518 | - bool ret = false; |
519 | json_object* json_response = NULL; |
520 | const char* c_response = NULL; |
521 | - |
522 | - |
523 | if (!json_object_object_get_ex(root, key.c_str(), &json_response)) { |
524 | goto cleanup; |
525 | } |
526 | @@ -962,13 +995,13 @@ cleanup: |
527 | } |
528 | |
529 | bool ParseJsonToChallenges(const string& json, std::vector<Challenge>* challenges) { |
530 | - json_object* root = NULL; |
531 | - root = json_tokener_parse(json.c_str()); |
532 | + bool ret = false; |
533 | + |
534 | + json_object* root = ParseJsonRoot(json); |
535 | if (root == NULL) { |
536 | - return false; |
537 | + return ret; |
538 | } |
539 | |
540 | - bool ret = false; |
541 | json_object* challengeId = NULL; |
542 | json_object* challengeType = NULL; |
543 | json_object* challengeStatus = NULL; |
544 | @@ -1260,18 +1293,18 @@ static bool ApplyPolicy(const char *user_name, string email, const char *policy, |
545 | long http_code = 0; |
546 | // Invalid user, just leave from here - the principal will not be allowed/authorized. |
547 | if (!HttpGet(url.str(), &response, &http_code)) { |
548 | - SysLogErr("Failed to validate organization user %s has login permission.", user_name); |
549 | + SysLogErr("Failed to validate that OS Login user %s has %s permission.", user_name, policy); |
550 | return false; |
551 | } |
552 | |
553 | if (http_code != 200) { |
554 | - SysLogErr("Failed to validate organization user %s has login permission, " |
555 | - "got HTTP response code: %lu", user_name, http_code); |
556 | + SysLogErr("Failed to validate that OS Login user %s has %s permission; " |
557 | + "got HTTP response code: %lu", user_name, policy, http_code); |
558 | return false; |
559 | } |
560 | |
561 | if (!ParseJsonToSuccess(response)) { |
562 | - SysLogErr("Organization user %s does not have login permission.", user_name); |
563 | + SysLogErr("OS Login user %s does not have %s permission.", user_name, policy); |
564 | return false; |
565 | } |
566 | |
567 | @@ -1369,6 +1402,9 @@ bool AuthorizeUser(const char *user_name, struct AuthOptions opts, string *user_ |
568 | } |
569 | } else { |
570 | remove(sudoers_filename.c_str()); |
571 | + if (opts.admin_policy_required) { |
572 | + return false; |
573 | + } |
574 | } |
575 | |
576 | return true; |
577 | diff --git a/src/pam/pam_oslogin_admin.cc b/src/pam/pam_oslogin_admin.cc |
578 | new file mode 100644 |
579 | index 0000000..06bb10b |
580 | --- /dev/null |
581 | +++ b/src/pam/pam_oslogin_admin.cc |
582 | @@ -0,0 +1,53 @@ |
583 | +// Copyright 2024 Google Inc. All Rights Reserved. |
584 | +// |
585 | +// Licensed under the Apache License, Version 2.0 (the "License"); |
586 | +// you may not use this file except in compliance with the License. |
587 | +// You may obtain a copy of the License at |
588 | +// |
589 | +// http://www.apache.org/licenses/LICENSE-2.0 |
590 | +// |
591 | +// Unless required by applicable law or agreed to in writing, software |
592 | +// distributed under the License is distributed on an "AS IS" BASIS, |
593 | +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
594 | +// See the License for the specific language governing permissions and |
595 | +// limitations under the License. |
596 | + |
597 | +#include <security/pam_modules.h> |
598 | + |
599 | +#include <compat.h> |
600 | +#include <oslogin_utils.h> |
601 | + |
602 | +using std::string; |
603 | + |
604 | +using oslogin_utils::AuthOptions; |
605 | + |
606 | +extern "C" { |
607 | + |
608 | +// pm_sm_acct_mgmt is the account management PAM implementation for admin users (or users |
609 | +// with the proper loginAdmin policy). This account management module is intended for custom |
610 | +// configuration handling only, where users need a way to in their stack configurations to |
611 | +// differentiate a OS Login user. The Google Guest Agent will not manage the lifecycle of |
612 | +// this module, it will not add this to the stack as part of the standard/default configuration |
613 | +// set. |
614 | +PAM_EXTERN int |
615 | +pam_sm_acct_mgmt(pam_handle_t* pamh, int flags, int argc, const char** argv) { |
616 | + struct AuthOptions opts; |
617 | + const char *user_name; |
618 | + string user_response; |
619 | + |
620 | + if (pam_get_user(pamh, &user_name, NULL) != PAM_SUCCESS) { |
621 | + PAM_SYSLOG(pamh, LOG_INFO, "Could not get pam user."); |
622 | + return PAM_PERM_DENIED; |
623 | + } |
624 | + |
625 | + opts = { 0 }; |
626 | + opts.admin_policy_required = true; |
627 | + |
628 | + if (!AuthorizeUser(user_name, opts, &user_response)) { |
629 | + return PAM_PERM_DENIED; |
630 | + } |
631 | + |
632 | + return PAM_SUCCESS; |
633 | +} |
634 | + |
635 | +} |
636 | diff --git a/src/pam/pam_oslogin_login.cc b/src/pam/pam_oslogin_login.cc |
637 | index ca41ed3..5d863d2 100644 |
638 | --- a/src/pam/pam_oslogin_login.cc |
639 | +++ b/src/pam/pam_oslogin_login.cc |
640 | @@ -22,6 +22,7 @@ |
641 | #include <compat.h> |
642 | #include <oslogin_utils.h> |
643 | |
644 | +using oslogin_utils::AuthOptions; |
645 | using oslogin_utils::ContinueSession; |
646 | using oslogin_utils::GetUser; |
647 | using oslogin_utils::ParseJsonToChallenges; |
648 | @@ -32,6 +33,32 @@ using oslogin_utils::ValidateUserName; |
649 | |
650 | extern "C" { |
651 | |
652 | +// pm_sm_acct_mgmt is the account management PAM implementation for non-admin users (or users |
653 | +// without the proper loginAdmin policy). This account management module is intended for custom |
654 | +// configuration handling only, where users need a way to in their stack configurations to |
655 | +// differentiate a OS Login user. The Google Guest Agent will not manage the lifecycle of |
656 | +// this module, it will not add this to the stack as part of the standard/default configuration |
657 | +// set. |
658 | +PAM_EXTERN int |
659 | +pam_sm_acct_mgmt(pam_handle_t* pamh, int flags, int argc, const char** argv) { |
660 | + struct AuthOptions opts; |
661 | + const char *user_name; |
662 | + string user_response; |
663 | + |
664 | + if (pam_get_user(pamh, &user_name, NULL) != PAM_SUCCESS) { |
665 | + PAM_SYSLOG(pamh, LOG_INFO, "Could not get pam user."); |
666 | + return PAM_PERM_DENIED; |
667 | + } |
668 | + |
669 | + opts = { 0 }; |
670 | + |
671 | + if (!AuthorizeUser(user_name, opts, &user_response)) { |
672 | + return PAM_PERM_DENIED; |
673 | + } |
674 | + |
675 | + return PAM_SUCCESS; |
676 | +} |
677 | + |
678 | PAM_EXTERN int |
679 | pam_sm_setcred(pam_handle_t* pamh, int flags, int argc, const char** argv) { |
680 | return PAM_SUCCESS; |
681 | diff --git a/test/oslogin_utils_test.cc b/test/oslogin_utils_test.cc |
682 | index 3451f61..0646a34 100644 |
683 | --- a/test/oslogin_utils_test.cc |
684 | +++ b/test/oslogin_utils_test.cc |
685 | @@ -460,6 +460,13 @@ TEST(GetGroupByTest, GetGroupByGIDSucceeds) { |
686 | ASSERT_EQ(errnop, 0); |
687 | } |
688 | |
689 | +TEST(CurlClient, RetryLogic) { |
690 | + ASSERT_FALSE(ShouldRetry(200)); |
691 | + ASSERT_FALSE(ShouldRetry(404)); |
692 | + ASSERT_FALSE(ShouldRetry(400)); |
693 | + ASSERT_TRUE(ShouldRetry(429)); |
694 | +} |
695 | + |
696 | TEST(ParseJsonEmailTest, SuccessfullyParsesEmail) { |
697 | string test_user = |
698 | "{\"loginProfiles\":[{\"name\":\"foo@example.com\",\"posixAccounts\":[" |
Hey,
Thank you for the MP, it looks good but it doesn't do the right .so replacement.
I am wondering how'd it work for you? Do any of the tests test the .so?