Merge ~kajiya/+git/google-compute-engine-oslogin:update-bionic-to-20240701.00 into ~ubuntu-core-dev/+git/google-compute-engine-oslogin:ubuntu/bionic

Proposed by Chloé Smith
Status: Merged
Merged at revision: 59a86c032ca9166fe1f9dbf3855cb45fea2fa633
Proposed branch: ~kajiya/+git/google-compute-engine-oslogin:update-bionic-to-20240701.00
Merge into: ~ubuntu-core-dev/+git/google-compute-engine-oslogin:ubuntu/bionic
Diff against target: 785 lines (+319/-91)
12 files modified
OWNERS (+2/-2)
debian/changelog (+48/-0)
debian/links (+2/-2)
debian/patches/0002-inherit-cflags.patch (+23/-0)
debian/patches/series (+1/-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)
Reviewer Review Type Date Requested Status
Utkarsh Gupta Approve
Review via email: mp+471854@code.launchpad.net

Commit message

* d/ch entry for bionic
* Merge remote-tracking branch 'ubuntu-core-dev/ubuntu/focal' into 'ubuntu-core-dev/ubuntu/bionic'

Description of the change

To post a comment you must log in.
Revision history for this message
Utkarsh Gupta (utkarsh) wrote :

Thank you. Sponsored -

$ dput esm-apps:bionic ../google-compute-engine-oslogin_20240701.00-0ubuntu1\~18.04.0_source.changes
Uploading google-compute-engine-oslogin using ftp to esm-apps (host: ppa.launchpad.net; directory: ~ubuntu-esm/esm-apps-updates-staging/ubuntu/bionic)
running allowed-distribution: check whether a local profile permits uploads to the target distribution
running checksum: verify checksums before uploading
running suite-mismatch: check the target distribution for common errors
running gpg: check GnuPG signatures before the upload
Uploading google-compute-engine-oslogin_20240701.00-0ubuntu1~18.04.0.dsc
Uploading google-compute-engine-oslogin_20240701.00.orig.tar.gz
Uploading google-compute-engine-oslogin_20240701.00-0ubuntu1~18.04.0.debian.tar.xz
Uploading google-compute-engine-oslogin_20240701.00-0ubuntu1~18.04.0_source.buildinfo
Uploading google-compute-engine-oslogin_20240701.00-0ubuntu1~18.04.0_source.changes

review: Approve

Preview Diff

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

Subscribers

People subscribed via source and target branches