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