diff -Nru google-compute-engine-oslogin-20210728.00/debian/changelog google-compute-engine-oslogin-20210907.00/debian/changelog --- google-compute-engine-oslogin-20210728.00/debian/changelog 2021-08-05 18:16:41.000000000 +0530 +++ google-compute-engine-oslogin-20210907.00/debian/changelog 2021-09-23 16:45:25.000000000 +0530 @@ -1,3 +1,17 @@ +google-compute-engine-oslogin (20210907.00-0ubuntu1) impish; urgency=medium + + * New upstream version 20210907.00. + - fix packaging for authorized_keys_sk (#68). + - fix double free in ParseJsonToKey (#70). + - include cstdlib for exit (#75). + - use sigaction for signals (#76). + * d/p/0002-fix-double-free-in-ParseJsonToKey.patch: drop + patch as it is included in this upstream release. + * d/links: Update links w/ respective .so shipped + * d/lintian-overrides: no manpage for google_authorized_keys_sk. + + -- Utkarsh Gupta Thu, 23 Sep 2021 16:45:25 +0530 + google-compute-engine-oslogin (20210728.00-0ubuntu1) impish; urgency=medium * New upstream version 20210728.00. (LP: #1938289) diff -Nru google-compute-engine-oslogin-20210728.00/debian/links google-compute-engine-oslogin-20210907.00/debian/links --- google-compute-engine-oslogin-20210728.00/debian/links 2021-08-05 18:16:41.000000000 +0530 +++ google-compute-engine-oslogin-20210907.00/debian/links 2021-09-23 16:45:25.000000000 +0530 @@ -1,2 +1,2 @@ -lib/libnss_cache_oslogin-20210728.00.so lib/libnss_cache_oslogin.so.2 -lib/libnss_oslogin-20210728.00.so lib/libnss_oslogin.so.2 +lib/libnss_cache_oslogin-20210907.00.so lib/libnss_cache_oslogin.so.2 +lib/libnss_oslogin-20210907.00.so lib/libnss_oslogin.so.2 diff -Nru google-compute-engine-oslogin-20210728.00/debian/lintian-overrides google-compute-engine-oslogin-20210907.00/debian/lintian-overrides --- google-compute-engine-oslogin-20210728.00/debian/lintian-overrides 2021-07-28 19:11:20.000000000 +0530 +++ google-compute-engine-oslogin-20210907.00/debian/lintian-overrides 2021-09-23 16:45:25.000000000 +0530 @@ -2,6 +2,7 @@ google-compute-engine-oslogin: maintainer-script-empty prerm # upstream does not provide manpages for those instrastructure scripts google-compute-engine-oslogin: binary-without-manpage usr/bin/google_authorized_keys +google-compute-engine-oslogin: binary-without-manpage usr/bin/google_authorized_keys_sk google-compute-engine-oslogin: binary-without-manpage usr/bin/google_oslogin_control google-compute-engine-oslogin: binary-without-manpage usr/bin/google_oslogin_nss_cache # wontfix, ther is no plan to split the shared libraries out of the package diff -Nru google-compute-engine-oslogin-20210728.00/debian/patches/0002-fix-double-free-in-ParseJsonToKey.patch google-compute-engine-oslogin-20210907.00/debian/patches/0002-fix-double-free-in-ParseJsonToKey.patch --- google-compute-engine-oslogin-20210728.00/debian/patches/0002-fix-double-free-in-ParseJsonToKey.patch 2021-08-05 18:16:41.000000000 +0530 +++ google-compute-engine-oslogin-20210907.00/debian/patches/0002-fix-double-free-in-ParseJsonToKey.patch 1970-01-01 05:30:00.000000000 +0530 @@ -1,24 +0,0 @@ -From a1e2623dbcfd43398789bdd89c05bfce0fca1407 Mon Sep 17 00:00:00 2001 -From: Liam Hopkins -Date: Thu, 5 Aug 2021 15:05:53 -0700 -Subject: [PATCH] fix double free in ParseJsonToKey - ---- - src/oslogin_utils.cc | 2 -- - 1 file changed, 2 deletions(-) - ---- a/src/oslogin_utils.cc -+++ b/src/oslogin_utils.cc -@@ -815,12 +815,10 @@ - - - if (!json_object_object_get_ex(root, key.c_str(), &json_response)) { -- json_object_put(root); - goto cleanup; - } - - if (!(c_response = json_object_get_string(json_response))) { -- json_object_put(root); - goto cleanup; - } - diff -Nru google-compute-engine-oslogin-20210728.00/debian/patches/series google-compute-engine-oslogin-20210907.00/debian/patches/series --- google-compute-engine-oslogin-20210728.00/debian/patches/series 2021-08-05 18:16:41.000000000 +0530 +++ google-compute-engine-oslogin-20210907.00/debian/patches/series 2021-09-23 16:45:25.000000000 +0530 @@ -1,2 +1 @@ 0001-set-LDFLAGS-to-prevent-undefs.patch -0002-fix-double-free-in-ParseJsonToKey.patch diff -Nru google-compute-engine-oslogin-20210728.00/packaging/google-compute-engine-oslogin.spec google-compute-engine-oslogin-20210907.00/packaging/google-compute-engine-oslogin.spec --- google-compute-engine-oslogin-20210728.00/packaging/google-compute-engine-oslogin.spec 2021-07-24 03:58:39.000000000 +0530 +++ google-compute-engine-oslogin-20210907.00/packaging/google-compute-engine-oslogin.spec 2021-09-07 23:54:06.000000000 +0530 @@ -73,6 +73,7 @@ /%{_lib}/security/pam_oslogin_admin.so /%{_lib}/security/pam_oslogin_login.so /usr/bin/google_authorized_keys +/usr/bin/google_authorized_keys_sk /usr/bin/google_oslogin_control /usr/bin/google_oslogin_nss_cache /usr/share/selinux/packages/oslogin.pp diff -Nru google-compute-engine-oslogin-20210728.00/src/authorized_keys/authorized_keys.cc google-compute-engine-oslogin-20210907.00/src/authorized_keys/authorized_keys.cc --- google-compute-engine-oslogin-20210728.00/src/authorized_keys/authorized_keys.cc 2021-07-24 03:58:39.000000000 +0530 +++ google-compute-engine-oslogin-20210907.00/src/authorized_keys/authorized_keys.cc 2021-09-07 23:54:06.000000000 +0530 @@ -12,10 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include #include #include +#include + #include using std::cout; @@ -24,17 +27,31 @@ using oslogin_utils::HttpGet; using oslogin_utils::ParseJsonToSuccess; -using oslogin_utils::ParseJsonToKey; using oslogin_utils::ParseJsonToEmail; using oslogin_utils::ParseJsonToSshKeys; using oslogin_utils::UrlEncode; using oslogin_utils::kMetadataServerUrl; +void sigpipe_handler(int signo) { + // exit 0 so SSHD can use what we've already written out. + _Exit(0); +} + int main(int argc, char* argv[]) { if (argc != 2) { cout << "usage: authorized_keys [username]" << endl; return 1; } + + struct sigaction newact; + newact.sa_handler = sigpipe_handler; + sigemptyset(&newact.sa_mask); + newact.sa_flags = 0; + if (sigaction(SIGPIPE, &newact, NULL) == -1) { + cout << "Unable to add SIGPIPE handler, exiting" << endl; + return 1; + } + std::stringstream url; url << kMetadataServerUrl << "users?username=" << UrlEncode(argv[1]); string user_response; @@ -44,6 +61,7 @@ if (http_code == 404) { // Return 0 if the user is not an oslogin user. If we returned a failure // code, we would populate auth.log with useless error messages. + // This exits successfully but prints no keys. return 0; } return 1; diff -Nru google-compute-engine-oslogin-20210728.00/src/authorized_keys/authorized_keys_sk.cc google-compute-engine-oslogin-20210907.00/src/authorized_keys/authorized_keys_sk.cc --- google-compute-engine-oslogin-20210728.00/src/authorized_keys/authorized_keys_sk.cc 1970-01-01 05:30:00.000000000 +0530 +++ google-compute-engine-oslogin-20210907.00/src/authorized_keys/authorized_keys_sk.cc 2021-09-07 23:54:06.000000000 +0530 @@ -0,0 +1,105 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include +#include + +#include + +using std::cout; +using std::endl; +using std::string; + +using oslogin_utils::HttpGet; +using oslogin_utils::ParseJsonToSuccess; +using oslogin_utils::ParseJsonToEmail; +using oslogin_utils::ParseJsonToSshKeys; +using oslogin_utils::ParseJsonToSshKeysSk; +using oslogin_utils::UrlEncode; +using oslogin_utils::kMetadataServerUrl; + +void sigpipe_handler(int signo) { + // exit 0 so SSHD can use what we've already written out. + _Exit(0); +} + +int main(int argc, char* argv[]) { + if (argc != 2) { + cout << "usage: authorized_keys_sk [username]" << endl; + return 1; + } + + struct sigaction newact; + newact.sa_handler = sigpipe_handler; + sigemptyset(&newact.sa_mask); + newact.sa_flags = 0; + if (sigaction(SIGPIPE, &newact, NULL) == -1) { + cout << "Unable to add SIGPIPE handler, exiting" << endl; + return 1; + } + + bool is_sa = (strncmp(argv[1], "sa_", 3) == 0); + std::stringstream url; + url << kMetadataServerUrl << "users?username=" << UrlEncode(argv[1]) + << "&view=securityKey"; + string user_response; + long http_code = 0; + if (!HttpGet(url.str(), &user_response, &http_code) || + user_response.empty() || http_code != 200) { + if (http_code == 404) { + // Return 0 if the user is not an oslogin user. If we returned a failure + // code, we would populate auth.log with useless error messages. + return 0; + } + return 1; + } + string email; + if (!ParseJsonToEmail(user_response, &email) || email.empty()) { + return 1; + } + // Redundantly verify that this user has permission to log in to this VM. + // Normally the PAM module determines this, but in the off chance a transient + // error causes the PAM module to permit a user without login permissions, + // perform the same check here. If this fails, we can guarantee that we won't + // accidentally allow a user to log in without permissions. + url.str(""); + url << kMetadataServerUrl << "authorize?email=" << UrlEncode(email) + << "&policy=login"; + string auth_response; + if (!HttpGet(url.str(), &auth_response, &http_code) || http_code != 200 || + auth_response.empty()) { + return 1; + } + if (!ParseJsonToSuccess(auth_response)) { + return 1; + } + // At this point, we've verified the user can log in. Grab the ssh keys from + // the user response. + std::vector ssh_keys; + if (is_sa) { + // Service accounts should continue to function when SK is enabled. + ssh_keys = ParseJsonToSshKeys(user_response); + } else { + ssh_keys = ParseJsonToSshKeysSk(user_response); + } + for (size_t i = 0; i < ssh_keys.size(); i++) { + cout << ssh_keys[i] << endl; + } + return 0; +} diff -Nru google-compute-engine-oslogin-20210728.00/src/include/oslogin_utils.h google-compute-engine-oslogin-20210907.00/src/include/oslogin_utils.h --- google-compute-engine-oslogin-20210728.00/src/include/oslogin_utils.h 2021-07-24 03:58:39.000000000 +0530 +++ google-compute-engine-oslogin-20210907.00/src/include/oslogin_utils.h 2021-09-07 23:54:06.000000000 +0530 @@ -247,6 +247,7 @@ // ssh_keys. A key is considered valid if it's expiration date is greater than // current unix time. std::vector ParseJsonToSshKeys(const string& json); +std::vector ParseJsonToSshKeysSk(const string& json); // Parses a JSON object and returns the value associated with a given key. bool ParseJsonToKey(const string& json, const string& key, string* response); diff -Nru google-compute-engine-oslogin-20210728.00/src/Makefile google-compute-engine-oslogin-20210907.00/src/Makefile --- google-compute-engine-oslogin-20210728.00/src/Makefile 2021-07-24 03:58:39.000000000 +0530 +++ google-compute-engine-oslogin-20210907.00/src/Makefile 2021-09-07 23:54:06.000000000 +0530 @@ -30,7 +30,7 @@ PAM_LOGIN = pam_oslogin_login.so PAM_ADMIN = pam_oslogin_admin.so -BINARIES = google_oslogin_nss_cache google_authorized_keys +BINARIES = google_oslogin_nss_cache google_authorized_keys google_authorized_keys_sk all : $(NSS_OSLOGIN) $(NSS_CACHE_OSLOGIN) $(PAM_LOGIN) $(PAM_ADMIN) $(BINARIES) @@ -63,6 +63,9 @@ google_authorized_keys : authorized_keys/authorized_keys.o oslogin_utils.o $(CXX) $(CXXFLAGS) $(CPPFLAGS) $^ -o $@ $(LDLIBS) +google_authorized_keys_sk : authorized_keys/authorized_keys_sk.o oslogin_utils.o + $(CXX) $(CXXFLAGS) $(CPPFLAGS) $^ -o $@ $(LDLIBS) + google_oslogin_nss_cache: cache_refresh/cache_refresh.o oslogin_utils.o $(CXX) $(CXXFLAGS) $(CPPFLAGS) $^ -o $@ $(LDLIBS) diff -Nru google-compute-engine-oslogin-20210728.00/src/oslogin_utils.cc google-compute-engine-oslogin-20210907.00/src/oslogin_utils.cc --- google-compute-engine-oslogin-20210728.00/src/oslogin_utils.cc 2021-07-24 03:58:39.000000000 +0530 +++ google-compute-engine-oslogin-20210907.00/src/oslogin_utils.cc 2021-09-07 23:54:06.000000000 +0530 @@ -542,7 +542,7 @@ result->gr_gid = gr_gid; if (!buf->AppendString("", &result->gr_passwd, errnop)) goto cleanup; - if (!buf->AppendString((char*)json_object_get_string(name), &result->gr_name, + if (!buf->AppendString(json_object_get_string(name), &result->gr_name, errnop)) goto cleanup; @@ -599,7 +599,7 @@ if (val_type != json_type_string) { continue; } - key_to_add = (char*)json_object_get_string(val); + key_to_add = json_object_get_string(val); } if (string_key == "expirationTimeUsec") { if (val_type == json_type_int || val_type == json_type_string) { @@ -624,6 +624,62 @@ return result; } +std::vector ParseJsonToSshKeysSk(const string& json) { + std::vector result; + json_object* security_keys = NULL; + + json_object* root = NULL; + root = json_tokener_parse(json.c_str()); + if (root == NULL) { + return result; + } + + // Locate the securityKeys array. + json_object* login_profiles = NULL; + if (!json_object_object_get_ex(root, "loginProfiles", &login_profiles)) { + goto cleanup; + } + if (json_object_get_type(login_profiles) != json_type_array) { + goto cleanup; + } + + login_profiles = json_object_array_get_idx(login_profiles, 0); + + if (!json_object_object_get_ex(login_profiles, "securityKeys", &security_keys)) { + goto cleanup; + } + if (json_object_get_type(security_keys) != json_type_array) { + goto cleanup; + } + + { + size_t number_of_keys = 0; + size_t idx; + json_object* security_key = NULL; + json_object* public_key = NULL; + string key_to_add = ""; + + number_of_keys = json_object_array_length(security_keys); + for (idx = 0; idx < number_of_keys; idx++) { + security_key = json_object_array_get_idx(security_keys, idx); + if (json_object_get_type(security_key) != json_type_object) { + goto cleanup; + } + if (!json_object_object_get_ex(security_key, "publicKey", &public_key)) { + goto cleanup; + } + + key_to_add = json_object_get_string(public_key); + result.push_back(key_to_add); + key_to_add.clear(); + } + } + +cleanup: + json_object_put(root); + return result; +} + bool ParseJsonToPasswd(const string& json, struct passwd* result, BufferManager* buf, int* errnop) { *errnop = EINVAL; @@ -699,7 +755,7 @@ if (val_type != json_type_string) { goto cleanup; } - if (!buf->AppendString((char*)json_object_get_string(val), + if (!buf->AppendString(json_object_get_string(val), &result->pw_name, errnop)) { goto cleanup; } @@ -707,7 +763,7 @@ if (val_type != json_type_string) { goto cleanup; } - if (!buf->AppendString((char*)json_object_get_string(val), + if (!buf->AppendString(json_object_get_string(val), &result->pw_dir, errnop)) { goto cleanup; } @@ -715,7 +771,7 @@ if (val_type != json_type_string) { goto cleanup; } - if (!buf->AppendString((char*)json_object_get_string(val), + if (!buf->AppendString(json_object_get_string(val), &result->pw_shell, errnop)) { goto cleanup; } @@ -815,12 +871,10 @@ if (!json_object_object_get_ex(root, key.c_str(), &json_response)) { - json_object_put(root); goto cleanup; } if (!(c_response = json_object_get_string(json_response))) { - json_object_put(root); goto cleanup; }