diff options
Diffstat (limited to 'packages/google-compute-engine-oslogin/src')
12 files changed, 0 insertions, 2455 deletions
diff --git a/packages/google-compute-engine-oslogin/src/Makefile b/packages/google-compute-engine-oslogin/src/Makefile deleted file mode 100644 index 8b5d339..0000000 --- a/packages/google-compute-engine-oslogin/src/Makefile +++ /dev/null @@ -1,86 +0,0 @@ -SHELL = /bin/sh -TOPDIR = $(realpath ..) - -VERSION = 20190801.00 - -CPPFLAGS = -Iinclude -I/usr/include/json-c -FLAGS = -fPIC -Wall -g -CFLAGS = $(FLAGS) -Wstrict-prototypes -CXXFLAGS = $(FLAGS) - -LDFLAGS = -shared -Wl,-soname,$(SONAME) -LDLIBS = -lcurl -ljson-c -PAMLIBS = -lpam $(LDLIBS) - -# Paths which should be overrideable. - -PREFIX = /usr -LIBDIR = $(PREFIX)/lib -BINDIR = $(PREFIX)/bin -PAMDIR = $(LIBDIR)/security -MANDIR = /usr/share/man - -NSS_OSLOGIN_SONAME = libnss_oslogin.so.2 -NSS_CACHE_OSLOGIN_SONAME = libnss_cache_oslogin.so.2 - -NSS_OSLOGIN = libnss_oslogin-$(VERSION).so -NSS_CACHE_OSLOGIN = libnss_cache_oslogin-$(VERSION).so - -PAM_LOGIN = pam_oslogin_login.so -PAM_ADMIN = pam_oslogin_admin.so - -BINARIES = google_oslogin_nss_cache google_authorized_keys - -all : $(NSS_OSLOGIN) $(NSS_CACHE_OSLOGIN) $(PAM_LOGIN) $(PAM_ADMIN) $(BINARIES) - -clean : - rm -f $(BINARIES) - find . -type f \( -iname '*.o' -o -iname '*.so' \) -delete - -.PHONY : all clean install - -# NSS modules. - -$(NSS_OSLOGIN) : SONAME = $(NSS_OSLOGIN_SONAME) -$(NSS_OSLOGIN) : nss/nss_oslogin.o utils.o - $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $^ -o $@ $(LDLIBS) - -$(NSS_CACHE_OSLOGIN) : SONAME = $(NSS_CACHE_OSLOGIN_SONAME) -$(NSS_CACHE_OSLOGIN) : nss/nss_cache_oslogin.o nss/compat/getpwent_r.o utils.o - $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $^ -o $@ $(LDLIBS) - -# PAM modules - -$(PAM_LOGIN) : pam/pam_oslogin_login.o utils.o - $(CXX) $(CXXFLAGS) $(CPPFLAGS) -shared $^ -o $@ $(PAMLIBS) - -$(PAM_ADMIN) : pam/pam_oslogin_admin.o utils.o - $(CXX) $(CXXFLAGS) $(CPPFLAGS) -shared $^ -o $@ $(PAMLIBS) - -# Utilities. - -google_authorized_keys : authorized_keys/authorized_keys.o utils.o - $(CXX) $(CXXFLAGS) $(CPPFLAGS) $^ -o $@ $(LDLIBS) - -google_oslogin_nss_cache: cache_refresh/cache_refresh.o utils.o - $(CXX) $(CXXFLAGS) $(CPPFLAGS) $^ -o $@ $(LDLIBS) - -install: all - install -d $(DESTDIR)$(LIBDIR) - install -d $(DESTDIR)$(PAMDIR) - install -d $(DESTDIR)$(BINDIR) - install -d $(DESTDIR)$(MANDIR)/man8 - install -m 0644 -t $(DESTDIR)$(LIBDIR) $(NSS_OSLOGIN) $(NSS_CACHE_OSLOGIN) - ln -sf $(NSS_OSLOGIN) $(DESTDIR)$(LIBDIR)/$(NSS_OSLOGIN_SONAME) - ln -sf $(NSS_CACHE_OSLOGIN) $(DESTDIR)$(LIBDIR)/$(NSS_CACHE_OSLOGIN_SONAME) - install -m 0644 -t $(DESTDIR)$(PAMDIR) $(PAM_ADMIN) $(PAM_LOGIN) - install -m 0755 -t $(DESTDIR)$(BINDIR) $(BINARIES) $(TOPDIR)/google_oslogin_control - install -m 0644 -t $(DESTDIR)$(MANDIR)/man8 $(TOPDIR)/man/nss-oslogin.8 $(TOPDIR)/man/nss-cache-oslogin.8 - gzip -9 $(DESTDIR)$(MANDIR)/man8/nss-oslogin.8 - gzip -9 $(DESTDIR)$(MANDIR)/man8/nss-cache-oslogin.8 - ln -sf nss-oslogin.8.gz $(DESTDIR)$(MANDIR)/man8/$(NSS_OSLOGIN_SONAME).8.gz - ln -sf nss-cache-oslogin.8.gz $(DESTDIR)$(MANDIR)/man8/$(NSS_CACHE_OSLOGIN_SONAME).8.gz -ifdef INSTALL_SELINUX - install -d $(DESTDIR)/usr/share/selinux/packages - install -m 0644 -t $(DESTDIR)/usr/share/selinux/packages $(TOPDIR)/selinux/oslogin.pp -endif diff --git a/packages/google-compute-engine-oslogin/src/authorized_keys/authorized_keys.cc b/packages/google-compute-engine-oslogin/src/authorized_keys/authorized_keys.cc deleted file mode 100644 index 3eda59c..0000000 --- a/packages/google-compute-engine-oslogin/src/authorized_keys/authorized_keys.cc +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2017 Google Inc. All Rights Reserved. -// -// 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 <iostream> -#include <sstream> -#include <string> - -#include <oslogin_utils.h> - -using std::cout; -using std::endl; -using std::string; - -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; - -int main(int argc, char* argv[]) { - if (argc != 2) { - cout << "usage: authorized_keys [username]" << endl; - return 1; - } - std::stringstream url; - url << kMetadataServerUrl << "users?username=" << UrlEncode(argv[1]); - 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<string> ssh_keys = ParseJsonToSshKeys(user_response); - for (int i = 0; i < ssh_keys.size(); i++) { - cout << ssh_keys[i] << endl; - } - return 0; -} diff --git a/packages/google-compute-engine-oslogin/src/cache_refresh/cache_refresh.cc b/packages/google-compute-engine-oslogin/src/cache_refresh/cache_refresh.cc deleted file mode 100644 index bc4a10c..0000000 --- a/packages/google-compute-engine-oslogin/src/cache_refresh/cache_refresh.cc +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2018 Google Inc. All Rights Reserved. -// -// 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 <errno.h> -#include <nss.h> -#include <pthread.h> -#include <pwd.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <syslog.h> -#include <unistd.h> - -#include <fstream> - -#include <compat.h> -#include <oslogin_utils.h> - - -using oslogin_utils::BufferManager; -using oslogin_utils::MutexLock; -using oslogin_utils::NssCache; - -// File paths for the nss cache file. -static const char kDefaultFilePath[] = K_DEFAULT_FILE_PATH; -static const char kDefaultBackupFilePath[] = K_DEFAULT_BACKUP_FILE_PATH; - -// Local NSS Cache size. This affects the maximum number of passwd entries per -// http request. -static const uint64_t kNssCacheSize = 2048; - -// Passwd buffer size. We are guaranteed that a single OS Login user will not -// exceed 32k. -static const uint64_t kPasswdBufferSize = 32768; - -static NssCache nss_cache(kNssCacheSize); - -static pthread_mutex_t cache_mutex = PTHREAD_MUTEX_INITIALIZER; - -int main(int argc, char* argv[]) { - int error_code = 0; - // Temporary buffer to hold passwd entries before writing. - char buffer[kPasswdBufferSize]; - struct passwd pwd; - - // Perform the writes under a global lock. - MutexLock ml(&cache_mutex); - nss_cache.Reset(); - - // Check if there is a cache already. - struct stat stat_buf; - bool backup = !stat(kDefaultFilePath, &stat_buf); - if (backup) { - // Write a backup file first, in case lookup fails. - error_code = rename(kDefaultFilePath, kDefaultBackupFilePath); - if (error_code) { - openlog("nss_cache_oslogin", LOG_PID, LOG_USER); - syslog(LOG_ERR, "Could not create backup file."); - closelog(); - return error_code; - } - } - - std::ofstream cache_file(kDefaultFilePath); - if (cache_file.fail()) { - openlog("nss_cache_oslogin", LOG_PID, LOG_USER); - syslog(LOG_ERR, "Failed to open file %s.", kDefaultFilePath); - closelog(); - return -1; - } - chown(kDefaultFilePath, 0, 0); - chmod(kDefaultFilePath, S_IRUSR | S_IWUSR | S_IROTH); - - while (!nss_cache.OnLastPage() || nss_cache.HasNextPasswd()) { - BufferManager buffer_manager(buffer, kPasswdBufferSize); - if (!nss_cache.NssGetpwentHelper(&buffer_manager, &pwd, &error_code)) { - break; - } - cache_file << pwd.pw_name << ":" << pwd.pw_passwd << ":" << pwd.pw_uid - << ":" << pwd.pw_gid << ":" << pwd.pw_gecos << ":" << pwd.pw_dir - << ":" << pwd.pw_shell << "\n"; - } - cache_file.close(); - - // Check for errors. - if (error_code) { - openlog("nss_cache_oslogin", LOG_PID, LOG_USER); - if (error_code == ERANGE) { - syslog(LOG_ERR, "Received unusually large passwd entry."); - } else if (error_code == EINVAL) { - syslog(LOG_ERR, "Encountered malformed passwd entry."); - } else { - syslog(LOG_ERR, "Unknown error while retrieving passwd entry."); - } - // Restore the backup. - if (backup) { - if (rename(kDefaultBackupFilePath, kDefaultFilePath)) { - syslog(LOG_ERR, "Could not restore data from backup file."); - } - } - closelog(); - } - - // Remove the backup file on success. - if (!error_code && backup) { - remove(kDefaultBackupFilePath); - } - return error_code; -} diff --git a/packages/google-compute-engine-oslogin/src/include/compat.h b/packages/google-compute-engine-oslogin/src/include/compat.h deleted file mode 100644 index 84a1a6f..0000000 --- a/packages/google-compute-engine-oslogin/src/include/compat.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2018 Google Inc. All Rights Reserved. -// -// 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. - -#ifndef OSLOGIN_COMPAT_H -#define OSLOGIN_COMPAT_H - -#ifdef __FreeBSD__ - -#include <nsswitch.h> - -#define DECLARE_NSS_METHOD_TABLE(name, ...) \ - static ns_mtab name[] = {__VA_ARGS__}; - -#define NSS_METHOD(method, func) { \ - .database = NSDB_PASSWD, \ - .name = #method, \ - .method = __nss_compat_ ## method, \ - .mdata = (void*)func \ -} - -#define NSS_REGISTER_METHODS(methods) ns_mtab * \ -nss_module_register (const char *name, unsigned int *size, \ - nss_module_unregister_fn *unregister) \ -{ \ - *size = sizeof (methods) / sizeof (methods[0]); \ - *unregister = NULL; \ - return (methods); \ -} - -#define NSS_CACHE_OSLOGIN_PATH "/usr/local/etc/oslogin_passwd.cache" -#define K_DEFAULT_FILE_PATH "/usr/local/etc/oslogin_passwd.cache" -#define K_DEFAULT_BACKUP_FILE_PATH "/usr/local/etc/oslogin_passwd.cache.bak" -#define PAM_SYSLOG(pamh, ...) syslog(__VA_ARGS__) -#define DEFAULT_SHELL "/bin/sh" - -#else /* __FreeBSD__ */ - -#include <security/pam_ext.h> - -#define DECLARE_NSS_METHOD_TABLE(name, ...) -#define NSS_CACHE_OSLOGIN_PATH "/etc/oslogin_passwd.cache" -#define NSS_METHOD_PROTOTYPE(m) -#define NSS_REGISTER_METHODS(methods) -#define K_DEFAULT_FILE_PATH "/etc/oslogin_passwd.cache" -#define K_DEFAULT_BACKUP_FILE_PATH "/etc/oslogin_passwd.cache.bak" -#define PAM_SYSLOG pam_syslog -#define DEFAULT_SHELL "/bin/bash" - -#endif /* __FreeBSD__ */ - -#endif /* OSLOGIN_COMPAT_H */ diff --git a/packages/google-compute-engine-oslogin/src/include/nss_cache_oslogin.h b/packages/google-compute-engine-oslogin/src/include/nss_cache_oslogin.h deleted file mode 100644 index 25c7274..0000000 --- a/packages/google-compute-engine-oslogin/src/include/nss_cache_oslogin.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2018 Google Inc. All Rights Reserved. -// -// 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 <errno.h> -#include <nss.h> -#include <stdlib.h> -#include <pwd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <sys/param.h> -#include <time.h> -#include <unistd.h> - -#ifndef NSS_CACHE_OSLOGIN_H -#define NSS_CACHE_OSLOGIN_H - -#ifdef DEBUG -#undef DEBUG -#define DEBUG(fmt, args...) \ - do { \ - fprintf(stderr, fmt, ##args); \ - } while (0) -#else -#define DEBUG(fmt, ...) \ - do { \ - } while (0) -#endif /* DEBUG */ - -#define NSS_CACHE_OSLOGIN_PATH_LENGTH 255 -extern char *_nss_cache_oslogin_setpwent_path(const char *path); - -enum nss_cache_oslogin_match { - NSS_CACHE_OSLOGIN_EXACT = 0, - NSS_CACHE_OSLOGIN_HIGH = 1, - NSS_CACHE_OSLOGIN_LOW = 2, - NSS_CACHE_OSLOGIN_ERROR = 3, -}; - -struct nss_cache_oslogin_args { - char *system_filename; - char *sorted_filename; - void *lookup_function; - void *lookup_value; - void *lookup_result; - char *buffer; - size_t buflen; - char *lookup_key; - size_t lookup_key_length; -}; - -#endif /* NSS_CACHE_OSLOGIN_H */ diff --git a/packages/google-compute-engine-oslogin/src/include/oslogin_utils.h b/packages/google-compute-engine-oslogin/src/include/oslogin_utils.h deleted file mode 100644 index 82763bf..0000000 --- a/packages/google-compute-engine-oslogin/src/include/oslogin_utils.h +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright 2017 Google Inc. All Rights Reserved. -// -// 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 <grp.h> -#include <pthread.h> -#include <pwd.h> -#include <stdint.h> - -#include <string> -#include <vector> - -#define TOTP "TOTP" -#define AUTHZEN "AUTHZEN" -#define INTERNAL_TWO_FACTOR "INTERNAL_TWO_FACTOR" -#define IDV_PREREGISTERED_PHONE "IDV_PREREGISTERED_PHONE" - -using std::string; -using std::vector; - -namespace oslogin_utils { - -// Metadata server URL. -static const char kMetadataServerUrl[] = - "http://metadata.google.internal/computeMetadata/v1/oslogin/"; - -// BufferManager encapsulates and manages a buffer and length. This class is not -// thread safe. -class BufferManager { - public: - // Create a BufferManager that will dole out chunks of buf as requested. - BufferManager(char* buf, size_t buflen); - - // Copies a string to the buffer and sets the buffer to point to that - // string. Copied string is guaranteed to be null-terminated. - // Returns false and sets errnop if there is not enough space left in the - // buffer for the string. - bool AppendString(const string& value, char** buffer, int* errnop); - - // Return a pointer to a buffer of size bytes. Returns NULL and sets errnop to - // ERANGE if there is not enough space left in the buffer for the request. - void* Reserve(size_t bytes, int* errnop); - - private: - // Whether there is space available in the buffer. - bool CheckSpaceAvailable(size_t bytes_to_write) const; - - char* buf_; - size_t buflen_; - - // Not copyable or assignable. - BufferManager& operator=(const BufferManager&); - BufferManager(const BufferManager&); -}; - -// Challenge represents a security challenge available to the user. -class Challenge { - public: - int id; - string type; - string status; -}; - -class Group { - public: - int64_t gid; - string name; -}; - -// NssCache caches passwd entries for getpwent_r. This is used to prevent making -// an HTTP call on every getpwent_r invocation. Stores up to cache_size entries -// at a time. This class is not thread safe. -class NssCache { - public: - explicit NssCache(int cache_size); - - // Clears and resets the NssCache. - void Reset(); - - // Whether the cache has a next passwd entry. - bool HasNextPasswd(); - - // Whether the cache has reached the last page of the database. - bool OnLastPage() { return on_last_page_; } - - // Grabs the next passwd entry. Returns true on success. Sets errnop on - // failure. - bool GetNextPasswd(BufferManager* buf, passwd* result, int* errnop); - - // Loads a json array of passwd entries in the cache, starting at the - // beginning of the cache. This will remove all previous entries in the cache. - // response is expected to be a JSON array of passwd entries. Returns - // true on success. - bool LoadJsonArrayToCache(string response); - - // Helper method that effectively implements the getpwent_r nss method. Each - // call will iterate through the OsLogin database and return the next entry. - // Internally, the cache will keep track of pages of passwd entries, and will - // make an http call to the server if necessary to retrieve additional - // entries. Returns whether passwd retrieval was successful. If true, the - // passwd result will contain valid data. - bool NssGetpwentHelper(BufferManager* buf, struct passwd* result, - int* errnop); - - // Returns the page token for requesting the next page of passwd entries. - string GetPageToken() { return page_token_; } - - private: - // The maximum size of the cache. - int cache_size_; - - // Vector of passwds. These are represented as stringified json object. - std::vector<std::string> passwd_cache_; - - // The page token for requesting the next page of passwds. - std::string page_token_; - - // Index for requesting the next passwd from the cache. - uint32_t index_; - - // Whether the NssCache has reached the last page of the database. - bool on_last_page_; - - // Not copyable or assignable. - NssCache& operator=(const NssCache&); - NssCache(const NssCache&); -}; - -// Auto locks and unlocks a given mutex on construction/destruction. Does NOT -// take ownership of the mutex. -class MutexLock { - public: - explicit MutexLock(pthread_mutex_t* mutex) : mutex_(mutex) { - pthread_mutex_lock(mutex_); - } - - ~MutexLock() { pthread_mutex_unlock(mutex_); } - - private: - // The mutex to lock/unlock - pthread_mutex_t* const mutex_; - - // Not copyable or assignable. - MutexLock& operator=(const MutexLock); - MutexLock(const MutexLock&); -}; - -// Callback invoked when Curl completes a request. -size_t OnCurlWrite(void* buf, size_t size, size_t nmemb, void* userp); - -// Uses Curl to issue a GET request to the given url. Returns whether the -// request was successful. If successful, the result from the server will be -// stored in response, and the HTTP response code will be stored in http_code. -bool HttpGet(const string& url, string* response, long* http_code); -bool HttpPost(const string& url, const string& data, string* response, - long* http_code); - -// Returns whether user_name is a valid OsLogin user name. -bool ValidateUserName(const string& user_name); - -// URL encodes the given parameter. Returns the encoded parameter. -std::string UrlEncode(const string& param); - -// Returns true if the given passwd contains valid fields. If pw_dir, pw_shell, -// or pw_passwd are not set, this will populate these entries with default -// values. -bool ValidatePasswd(struct passwd* result, BufferManager* buf, int* errnop); - -// Adds users and associated array of char* to provided buffer and store pointer -// to array in result.gr_mem. -bool AddUsersToGroup(std::vector<string> users, struct group* result, - BufferManager* buf, int* errnop); - -// Iterates through all groups until one matching provided group is found, -// replacing gr_name with a buffermanager provided string. -bool FindGroup(struct group* grp, BufferManager* buf, int* errnop); - -// Iterates through all users for a group, storing results in a provided string -// vector. -bool GetUsersForGroup(string groupname, std::vector<string>* users, - int* errnop); - -// Iterates through all groups for a user, storing results in a provided string -// vector. -bool GetGroupsForUser(string username, std::vector<Group>* groups, int* errnop); - -// Parses a JSON groups response, storing results in a provided Group vector. -bool ParseJsonToGroups(const string& json, std::vector<Group>* groups); - -// Parses a JSON users response, storing results in a provided string vector. -bool ParseJsonToUsers(const string& json, std::vector<string>* users); - -// Parses a JSON LoginProfiles response for SSH keys. Returns a vector of valid -// ssh_keys. A key is considered valid if it's expiration date is greater than -// current unix time. -std::vector<string> ParseJsonToSshKeys(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); - -// Parses a JSON LoginProfiles response and returns the email under the "name" -// field. -bool ParseJsonToEmail(const string& json, string* email); - -// Parses a JSON LoginProfiles response and populates the passwd struct with the -// corresponding values set in the JSON object. Returns whether the parse was -// successful or not. If unsuccessful, errnop will also be set. -bool ParseJsonToPasswd(const string& response, struct passwd* result, - BufferManager* buf, int* errnop); - -// Parses a JSON adminLogin or login response and returns whether the user has -// the requested privilege. -bool ParseJsonToSuccess(const string& json); - -// Parses a JSON startSession response into a vector of Challenge objects. -bool ParseJsonToChallenges(const string& json, vector<Challenge>* challenges); - -// Calls the startSession API. -bool StartSession(const string& email, string* response); - -// Calls the continueSession API. -bool ContinueSession(bool alt, const string& email, const string& user_token, - const string& session_id, const Challenge& challenge, - string* response); - -// Returns user information from the metadata server. -bool GetUser(const string& username, string* response); -} // namespace oslogin_utils diff --git a/packages/google-compute-engine-oslogin/src/nss/compat/getpwent_r.c b/packages/google-compute-engine-oslogin/src/nss/compat/getpwent_r.c deleted file mode 100644 index b1be6fc..0000000 --- a/packages/google-compute-engine-oslogin/src/nss/compat/getpwent_r.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * ---------------------------------------------------------------------- - * Copyright © 2005-2014 Rich Felker, et al. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * ---------------------------------------------------------------------- - * - * Adapted from http://www.musl-libc.org/ for libnss-cache - * Copyright © 2015 Kevin Bowling <k@kev009.com> - */ - -#include <sys/param.h> - -#ifdef BSD - -#include <pwd.h> -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> -#include <string.h> - -static unsigned atou(char **s) -{ - unsigned x; - for (x=0; **s-'0'<10U; ++*s) x=10*x+(**s-'0'); - return x; -} - -int fgetpwent_r(FILE *f, struct passwd *pw, char *line, size_t size, struct passwd **res) -{ - char *s; - int rv = 0; - for (;;) { - line[size-1] = '\xff'; - if ( (fgets(line, size, f) == NULL) || ferror(f) || line[size-1] != '\xff' ) { - rv = (line[size-1] != '\xff') ? ERANGE : ENOENT; - line = 0; - pw = 0; - break; - } - line[strcspn(line, "\n")] = 0; - - s = line; - pw->pw_name = s++; - if (!(s = strchr(s, ':'))) continue; - - *s++ = 0; pw->pw_passwd = s; - if (!(s = strchr(s, ':'))) continue; - - *s++ = 0; pw->pw_uid = atou(&s); - if (*s != ':') continue; - - *s++ = 0; pw->pw_gid = atou(&s); - if (*s != ':') continue; - - *s++ = 0; pw->pw_gecos = s; - if (!(s = strchr(s, ':'))) continue; - - *s++ = 0; pw->pw_dir = s; - if (!(s = strchr(s, ':'))) continue; - - *s++ = 0; pw->pw_shell = s; - break; - } - *res = pw; - if (rv) errno = rv; - return rv; -} - -#endif // ifdef BSD diff --git a/packages/google-compute-engine-oslogin/src/nss/nss_cache_oslogin.c b/packages/google-compute-engine-oslogin/src/nss/nss_cache_oslogin.c deleted file mode 100644 index 55bb78d..0000000 --- a/packages/google-compute-engine-oslogin/src/nss/nss_cache_oslogin.c +++ /dev/null @@ -1,274 +0,0 @@ -// Copyright 2018 Google Inc. All Rights Reserved. -// -// 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. - -// An NSS module which adds supports for file /etc/oslogin_passwd.cache - -#include <nss_cache_oslogin.h> -#include <compat.h> - -#include <sys/mman.h> - -// Locking implementation: use pthreads. -#include <pthread.h> -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -#define NSS_CACHE_OSLOGIN_LOCK() \ - do { \ - pthread_mutex_lock(&mutex); \ - } while (0) -#define NSS_CACHE_OSLOGIN_UNLOCK() \ - do { \ - pthread_mutex_unlock(&mutex); \ - } while (0) - -static FILE *p_file = NULL; -static char p_filename[NSS_CACHE_OSLOGIN_PATH_LENGTH] = NSS_CACHE_OSLOGIN_PATH; -#ifdef BSD -extern int fgetpwent_r(FILE *, struct passwd *, char *, size_t, - struct passwd **); -#endif // ifdef BSD - -/* Common return code routine for all *ent_r_locked functions. - * We need to return TRYAGAIN if the underlying files guy raises ERANGE, - * so that our caller knows to try again with a bigger buffer. - */ - -static inline enum nss_status _nss_cache_oslogin_ent_bad_return_code( - int errnoval) { - enum nss_status ret; - - switch (errnoval) { - case ERANGE: - DEBUG("ERANGE: Try again with a bigger buffer\n"); - ret = NSS_STATUS_TRYAGAIN; - break; - case ENOENT: - default: - DEBUG("ENOENT or default case: Not found\n"); - ret = NSS_STATUS_NOTFOUND; - }; - return ret; -} - -// -// Routines for passwd map defined below here -// - -// _nss_cache_oslogin_pwuid_wrap() -// Internal wrapper for binary searches, using uid-specific calls. - -static enum nss_cache_oslogin_match _nss_cache_oslogin_pwuid_wrap( - FILE *file, struct nss_cache_oslogin_args *args) { - struct passwd *result = args->lookup_result; - uid_t *uid = args->lookup_value; - - if (fgetpwent_r(file, result, args->buffer, args->buflen, &result) == 0) { - if (result->pw_uid == *uid) { - DEBUG("SUCCESS: found user %d:%s\n", result->pw_uid, result->pw_name); - return NSS_CACHE_OSLOGIN_EXACT; - } - DEBUG("Failed match at uid %d\n", result->pw_uid); - if (result->pw_uid > *uid) { - return NSS_CACHE_OSLOGIN_HIGH; - } else { - return NSS_CACHE_OSLOGIN_LOW; - } - } - - return NSS_CACHE_OSLOGIN_ERROR; -} - -// _nss_cache_oslogin_pwnam_wrap() -// Internal wrapper for binary searches, using username-specific calls. - -static enum nss_cache_oslogin_match _nss_cache_oslogin_pwnam_wrap( - FILE *file, struct nss_cache_oslogin_args *args) { - struct passwd *result = args->lookup_result; - char *name = args->lookup_value; - int ret; - - if (fgetpwent_r(file, result, args->buffer, args->buflen, &result) == 0) { - ret = strcoll(result->pw_name, name); - if (ret == 0) { - DEBUG("SUCCESS: found user %s\n", result->pw_name); - return NSS_CACHE_OSLOGIN_EXACT; - } - DEBUG("Failed match at name %s\n", result->pw_name); - if (ret > 0) { - return NSS_CACHE_OSLOGIN_HIGH; - } else { - return NSS_CACHE_OSLOGIN_LOW; - } - } - - return NSS_CACHE_OSLOGIN_ERROR; -} - -// _nss_cache_oslogin_setpwent_locked() -// Internal setup routine - -static enum nss_status _nss_cache_oslogin_setpwent_locked(void) { - DEBUG("%s %s\n", "Opening", p_filename); - p_file = fopen(p_filename, "r"); - - if (p_file) { - return NSS_STATUS_SUCCESS; - } else { - return NSS_STATUS_UNAVAIL; - } -} - -// _nss_cache_oslogin_setpwent() -// Called by NSS to open the passwd file -// 'stayopen' parameter is ignored. - -enum nss_status _nss_cache_oslogin_setpwent(int stayopen) { - enum nss_status ret; - NSS_CACHE_OSLOGIN_LOCK(); - ret = _nss_cache_oslogin_setpwent_locked(); - NSS_CACHE_OSLOGIN_UNLOCK(); - return ret; -} - -// _nss_cache_oslogin_endpwent_locked() -// Internal close routine - -static enum nss_status _nss_cache_oslogin_endpwent_locked(void) { - DEBUG("Closing passwd.cache\n"); - if (p_file) { - fclose(p_file); - p_file = NULL; - } - return NSS_STATUS_SUCCESS; -} - -// _nss_cache_oslogin_endpwent() -// Called by NSS to close the passwd file - -enum nss_status _nss_cache_oslogin_endpwent(void) { - enum nss_status ret; - NSS_CACHE_OSLOGIN_LOCK(); - ret = _nss_cache_oslogin_endpwent_locked(); - NSS_CACHE_OSLOGIN_UNLOCK(); - return ret; -} - -// _nss_cache_oslogin_getpwent_r_locked() -// Called internally to return the next entry from the passwd file - -static enum nss_status _nss_cache_oslogin_getpwent_r_locked( - struct passwd *result, char *buffer, size_t buflen, int *errnop) { - enum nss_status ret = NSS_STATUS_SUCCESS; - - if (p_file == NULL) { - DEBUG("p_file == NULL, going to setpwent\n"); - ret = _nss_cache_oslogin_setpwent_locked(); - } - - if (ret == NSS_STATUS_SUCCESS) { - if (fgetpwent_r(p_file, result, buffer, buflen, &result) == 0) { - DEBUG("Returning user %d:%s\n", result->pw_uid, result->pw_name); - } else { - if (errno == ENOENT) { - errno = 0; - } - *errnop = errno; - ret = _nss_cache_oslogin_ent_bad_return_code(*errnop); - } - } - - return ret; -} - -// _nss_cache_oslogin_getpwent_r() -// Called by NSS to look up next entry in passwd file - -enum nss_status _nss_cache_oslogin_getpwent_r(struct passwd *result, - char *buffer, size_t buflen, - int *errnop) { - enum nss_status ret; - NSS_CACHE_OSLOGIN_LOCK(); - ret = _nss_cache_oslogin_getpwent_r_locked(result, buffer, buflen, errnop); - NSS_CACHE_OSLOGIN_UNLOCK(); - return ret; -} - -// _nss_cache_oslogin_getpwuid_r() -// Find a user account by uid - -enum nss_status _nss_cache_oslogin_getpwuid_r(uid_t uid, struct passwd *result, - char *buffer, size_t buflen, - int *errnop) { - enum nss_status ret; - - NSS_CACHE_OSLOGIN_LOCK(); - ret = _nss_cache_oslogin_setpwent_locked(); - - if (ret == NSS_STATUS_SUCCESS) { - while ((ret = _nss_cache_oslogin_getpwent_r_locked( - result, buffer, buflen, errnop)) == NSS_STATUS_SUCCESS) { - if (result->pw_uid == uid) break; - } - } - - _nss_cache_oslogin_endpwent_locked(); - NSS_CACHE_OSLOGIN_UNLOCK(); - - return ret; -} - -// _nss_cache_oslogin_getpwnam_r() -// Find a user account by name - -enum nss_status _nss_cache_oslogin_getpwnam_r(const char *name, - struct passwd *result, - char *buffer, size_t buflen, - int *errnop) { - enum nss_status ret; - - NSS_CACHE_OSLOGIN_LOCK(); - ret = _nss_cache_oslogin_setpwent_locked(); - - if (ret == NSS_STATUS_SUCCESS) { - while ((ret = _nss_cache_oslogin_getpwent_r_locked( - result, buffer, buflen, errnop)) == NSS_STATUS_SUCCESS) { - if (!strcmp(result->pw_name, name)) break; - } - } - - _nss_cache_oslogin_endpwent_locked(); - NSS_CACHE_OSLOGIN_UNLOCK(); - - return ret; -} - -NSS_METHOD_PROTOTYPE(__nss_compat_getpwnam_r); -NSS_METHOD_PROTOTYPE(__nss_compat_getpwuid_r); -NSS_METHOD_PROTOTYPE(__nss_compat_getpwent_r); -NSS_METHOD_PROTOTYPE(__nss_compat_setpwent); -NSS_METHOD_PROTOTYPE(__nss_compat_endpwent); - -DECLARE_NSS_METHOD_TABLE(methods, - { NSDB_PASSWD, "getpwnam_r", __nss_compat_getpwnam_r, - (void*)_nss_cache_oslogin_getpwnam_r }, - { NSDB_PASSWD, "getpwuid_r", __nss_compat_getpwuid_r, - (void*)_nss_cache_oslogin_getpwuid_r }, - { NSDB_PASSWD, "getpwent_r", __nss_compat_getpwent_r, - (void*)_nss_cache_oslogin_getpwent_r }, - { NSDB_PASSWD, "endpwent", __nss_compat_endpwent, - (void*)_nss_cache_oslogin_endpwent }, - { NSDB_PASSWD, "setpwent", __nss_compat_setpwent, - (void*)_nss_cache_oslogin_setpwent }, -) - -NSS_REGISTER_METHODS(methods) diff --git a/packages/google-compute-engine-oslogin/src/nss/nss_oslogin.cc b/packages/google-compute-engine-oslogin/src/nss/nss_oslogin.cc deleted file mode 100644 index 2a34c83..0000000 --- a/packages/google-compute-engine-oslogin/src/nss/nss_oslogin.cc +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright 2017 Google Inc. All Rights Reserved. -// -// 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 <compat.h> -#include <curl/curl.h> -#include <errno.h> -#include <grp.h> -#include <nss.h> -#include <oslogin_utils.h> -#include <pthread.h> -#include <pwd.h> -#include <string.h> -#include <sys/param.h> -#include <sys/types.h> -#include <syslog.h> -#include <unistd.h> -#include <stdlib.h> - -#include <iostream> -#include <sstream> -#include <string> - -using std::string; - -using oslogin_utils::AddUsersToGroup; -using oslogin_utils::BufferManager; -using oslogin_utils::FindGroup; -using oslogin_utils::GetGroupsForUser; -using oslogin_utils::GetUsersForGroup; -using oslogin_utils::Group; -using oslogin_utils::HttpGet; -using oslogin_utils::kMetadataServerUrl; -using oslogin_utils::MutexLock; -using oslogin_utils::NssCache; -using oslogin_utils::ParseJsonToPasswd; -using oslogin_utils::UrlEncode; - -// Size of the NssCache. This also determines how many users will be requested -// per HTTP call. -static const uint64_t kNssCacheSize = 2048; - -// NssCache for storing passwd entries. -static NssCache nss_cache(kNssCacheSize); - -// Protects access to nss_cache. -static pthread_mutex_t cache_mutex = PTHREAD_MUTEX_INITIALIZER; - -extern "C" { - -// Get a passwd entry by id. -enum nss_status _nss_oslogin_getpwuid_r(uid_t uid, struct passwd *result, - char *buffer, size_t buflen, - int *errnop) { - BufferManager buffer_manager(buffer, buflen); - std::stringstream url; - url << kMetadataServerUrl << "users?uid=" << uid; - string response; - long http_code = 0; - if (!HttpGet(url.str(), &response, &http_code) || http_code != 200 || - response.empty()) { - *errnop = ENOENT; - return NSS_STATUS_NOTFOUND; - } - if (!ParseJsonToPasswd(response, result, &buffer_manager, errnop)) { - if (*errnop == EINVAL) { - openlog("nss_oslogin", LOG_PID, LOG_USER); - syslog(LOG_ERR, "Received malformed response from server: %s", - response.c_str()); - closelog(); - } - return *errnop == ERANGE ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND; - } - return NSS_STATUS_SUCCESS; -} - -// Get a passwd entry by name. -enum nss_status _nss_oslogin_getpwnam_r(const char *name, struct passwd *result, - char *buffer, size_t buflen, - int *errnop) { - BufferManager buffer_manager(buffer, buflen); - std::stringstream url; - url << kMetadataServerUrl << "users?username=" << UrlEncode(name); - string response; - long http_code = 0; - if (!HttpGet(url.str(), &response, &http_code) || http_code != 200 || - response.empty()) { - *errnop = ENOENT; - return NSS_STATUS_NOTFOUND; - } - if (!ParseJsonToPasswd(response, result, &buffer_manager, errnop)) { - if (*errnop == EINVAL) { - openlog("nss_oslogin", LOG_PID, LOG_USER); - syslog(LOG_ERR, "Received malformed response from server: %s", - response.c_str()); - closelog(); - } - return *errnop == ERANGE ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND; - } - return NSS_STATUS_SUCCESS; -} - -enum nss_status _nss_oslogin_getgrby(struct group *grp, char *buf, - size_t buflen, int *errnop) { - BufferManager buffer_manager(buf, buflen); - if (!FindGroup(grp, &buffer_manager, errnop)) - return *errnop == ERANGE ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND; - - std::vector<string> users; - if (!GetUsersForGroup(grp->gr_name, &users, errnop)) - return *errnop == ERANGE ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND; - - if (!AddUsersToGroup(users, grp, &buffer_manager, errnop)) - return *errnop == ERANGE ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND; - - return NSS_STATUS_SUCCESS; -} - -enum nss_status _nss_oslogin_getgrgid_r(gid_t gid, struct group *grp, char *buf, - size_t buflen, int *errnop) { - grp->gr_gid = gid; - return _nss_oslogin_getgrby(grp, buf, buflen, errnop); -} - -enum nss_status _nss_oslogin_getgrnam_r(const char *name, struct group *grp, - char *buf, size_t buflen, int *errnop) { - grp->gr_name = (char *)name; - return _nss_oslogin_getgrby(grp, buf, buflen, errnop); -} - -enum nss_status _nss_oslogin_initgroups_dyn(const char *user, gid_t skipgroup, - long int *start, long int *size, - gid_t **groupsp, long int limit, - int *errnop) { - std::vector<Group> grouplist; - if (!GetGroupsForUser(string(user), &grouplist, errnop)) { - return NSS_STATUS_NOTFOUND; - } - - gid_t *groups = *groupsp; - for (int i = 0; i < (int) grouplist.size(); i++) { - // Resize the buffer if needed. - if (*start == *size) { - gid_t *newgroups; - long int newsize = 2 * *size; - // Stop at limit if provided. - if (limit > 0) { - if (*size >= limit) { - *errnop = ERANGE; - return NSS_STATUS_TRYAGAIN; - } - newsize = MIN(limit, newsize); - } - newgroups = (gid_t *)realloc(groups, newsize * sizeof(gid_t *)); - if (newgroups == NULL) { - *errnop = EAGAIN; - return NSS_STATUS_TRYAGAIN; - } - *groupsp = groups = newgroups; - *size = newsize; - } - groups[(*start)++] = grouplist[i].gid; - } - return NSS_STATUS_SUCCESS; -} - -// nss_getpwent_r() is intentionally left unimplemented. This functionality is -// now covered by the nss_cache binary and nss_cache module. - -nss_status _nss_oslogin_getpwent_r() { return NSS_STATUS_NOTFOUND; } -nss_status _nss_oslogin_endpwent() { return NSS_STATUS_SUCCESS; } -nss_status _nss_oslogin_setpwent() { return NSS_STATUS_SUCCESS; } - -NSS_METHOD_PROTOTYPE(__nss_compat_getpwnam_r); -NSS_METHOD_PROTOTYPE(__nss_compat_getpwuid_r); -NSS_METHOD_PROTOTYPE(__nss_compat_getpwent_r); -NSS_METHOD_PROTOTYPE(__nss_compat_setpwent); -NSS_METHOD_PROTOTYPE(__nss_compat_endpwent); -NSS_METHOD_PROTOTYPE(__nss_compat_getgrnam_r); -NSS_METHOD_PROTOTYPE(__nss_compat_getgrgid_r); - -DECLARE_NSS_METHOD_TABLE(methods, - {NSDB_PASSWD, "getpwnam_r", __nss_compat_getpwnam_r, - (void *)_nss_oslogin_getpwnam_r}, - {NSDB_PASSWD, "getpwuid_r", __nss_compat_getpwuid_r, - (void *)_nss_oslogin_getpwuid_r}, - {NSDB_PASSWD, "getpwent_r", __nss_compat_getpwent_r, - (void *)_nss_oslogin_getpwent_r}, - {NSDB_PASSWD, "endpwent", __nss_compat_endpwent, - (void *)_nss_oslogin_endpwent}, - {NSDB_PASSWD, "setpwent", __nss_compat_setpwent, - (void *)_nss_oslogin_setpwent}, - {NSDB_GROUP, "getgrnam_r", __nss_compat_getgrnam_r, - (void *)_nss_oslogin_getgrnam_r}, - {NSDB_GROUP, "getgrgid_r", __nss_compat_getgrgid_r, - (void *)_nss_oslogin_getgrgid_r}, ) - -NSS_REGISTER_METHODS(methods) -} // extern "C" diff --git a/packages/google-compute-engine-oslogin/src/pam/pam_oslogin_admin.cc b/packages/google-compute-engine-oslogin/src/pam/pam_oslogin_admin.cc deleted file mode 100644 index 27abe53..0000000 --- a/packages/google-compute-engine-oslogin/src/pam/pam_oslogin_admin.cc +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2017 Google Inc. All Rights Reserved. -// -// 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. - -#define PAM_SM_ACCOUNT -#include <security/pam_appl.h> -#include <security/pam_modules.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <syslog.h> -#include <unistd.h> - -#include <iostream> -#include <fstream> -#include <sstream> -#include <string> - -#include <compat.h> -#include <oslogin_utils.h> - -using std::string; - -using oslogin_utils::HttpGet; -using oslogin_utils::GetUser; -using oslogin_utils::kMetadataServerUrl; -using oslogin_utils::ParseJsonToKey; -using oslogin_utils::ParseJsonToEmail; -using oslogin_utils::ParseJsonToSuccess; -using oslogin_utils::UrlEncode; -using oslogin_utils::ValidateUserName; - -static const char kSudoersDir[] = "/var/google-sudoers.d/"; - -extern "C" { - -PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, - const char **argv) { - // The return value for this module should generally be ignored. By default we - // will return PAM_SUCCESS. - int pam_result = PAM_SUCCESS; - const char *user_name; - if ((pam_result = pam_get_user(pamh, &user_name, NULL)) != PAM_SUCCESS) { - PAM_SYSLOG(pamh, LOG_INFO, "Could not get pam user."); - return pam_result; - } - - if (!ValidateUserName(user_name)) { - // If the user name is not a valid oslogin user, don't bother continuing. - return PAM_SUCCESS; - } - - string response; - if (!GetUser(user_name, &response)) { - return PAM_SUCCESS; - } - - string email; - if (!ParseJsonToEmail(response, &email) || email.empty()) { - return PAM_SUCCESS; - } - - std::stringstream url; - url << kMetadataServerUrl << "authorize?email=" << UrlEncode(email) - << "&policy=adminLogin"; - - string filename = kSudoersDir; - filename.append(user_name); - struct stat buffer; - bool file_exists = !stat(filename.c_str(), &buffer); - long http_code; - if (HttpGet(url.str(), &response, &http_code) && http_code == 200 && - ParseJsonToSuccess(response)) { - if (!file_exists) { - PAM_SYSLOG(pamh, LOG_INFO, - "Granting sudo permissions to organization user %s.", - user_name); - std::ofstream sudoers_file; - sudoers_file.open(filename.c_str()); - sudoers_file << user_name << " ALL=(ALL) NOPASSWD: ALL" - << "\n"; - sudoers_file.close(); - chown(filename.c_str(), 0, 0); - chmod(filename.c_str(), S_IRUSR | S_IRGRP); - } - } else if (file_exists) { - remove(filename.c_str()); - } - return pam_result; -} -} diff --git a/packages/google-compute-engine-oslogin/src/pam/pam_oslogin_login.cc b/packages/google-compute-engine-oslogin/src/pam/pam_oslogin_login.cc deleted file mode 100644 index 8ddec7b..0000000 --- a/packages/google-compute-engine-oslogin/src/pam/pam_oslogin_login.cc +++ /dev/null @@ -1,273 +0,0 @@ -// Copyright 2017 Google Inc. All Rights Reserved. -// -// 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. - -#define PAM_SM_ACCOUNT -#include <security/pam_appl.h> -#include <security/pam_modules.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <syslog.h> -#include <unistd.h> - -#include <iostream> -#include <fstream> -#include <sstream> -#include <string> -#include <map> - -#include <compat.h> -#include <oslogin_utils.h> - -using oslogin_utils::ContinueSession; -using oslogin_utils::GetUser; -using oslogin_utils::HttpGet; -using oslogin_utils::HttpPost; -using oslogin_utils::kMetadataServerUrl; -using oslogin_utils::ParseJsonToChallenges; -using oslogin_utils::ParseJsonToKey; -using oslogin_utils::ParseJsonToEmail; -using oslogin_utils::ParseJsonToSuccess; -using oslogin_utils::StartSession; -using oslogin_utils::UrlEncode; -using oslogin_utils::ValidateUserName; - -static const char kUsersDir[] = "/var/google-users.d/"; - -extern "C" { -PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, - const char **argv) { - const char *user_name; - if (pam_get_user(pamh, &user_name, NULL) != PAM_SUCCESS) { - PAM_SYSLOG(pamh, LOG_INFO, "Could not get pam user."); - return PAM_AUTH_ERR; - } - - if (!ValidateUserName(user_name)) { - // Not a valid OS Login username. - return PAM_IGNORE; - } - - std::string users_filename = kUsersDir; - users_filename.append(user_name); - struct stat buffer; - bool file_exists = !stat(users_filename.c_str(), &buffer); - - std::string str_user_name(user_name); - std::stringstream url; - url << kMetadataServerUrl << "users?username=" << UrlEncode(str_user_name); - - std::string response; - long http_code = 0; - if (!HttpGet(url.str(), &response, &http_code) || response.empty() || - http_code != 200) { - if (http_code == 404) { - // This module is only consulted for OS Login users. - return PAM_IGNORE; - } - - // Check local file for that user as a last resort. - if (file_exists) { - return PAM_PERM_DENIED; - } - - // We can't confirm this is an OS Login user, ignore module. - return PAM_IGNORE; - } - - std::string email; - if (!ParseJsonToEmail(response, &email) || email.empty()) { - return PAM_AUTH_ERR; - } - - url.str(""); - url << kMetadataServerUrl << "authorize?email=" << UrlEncode(email) - << "&policy=login"; - if (HttpGet(url.str(), &response, &http_code) && http_code == 200 && - ParseJsonToSuccess(response)) { - if (!file_exists) { - std::ofstream users_file(users_filename.c_str()); - chown(users_filename.c_str(), 0, 0); - chmod(users_filename.c_str(), S_IRUSR | S_IWUSR | S_IRGRP); - } - PAM_SYSLOG(pamh, LOG_INFO, - "Organization user %s has login permission.", - user_name); - return PAM_SUCCESS; - } else { - if (file_exists) { - remove(users_filename.c_str()); - } - PAM_SYSLOG(pamh, LOG_INFO, - "Organization user %s does not have login permission.", - user_name); - - return PAM_PERM_DENIED; - } -} - -PAM_EXTERN int pam_sm_setcred(pam_handle_t * pamh, int flags, int argc, - const char **argv) { - return PAM_SUCCESS; -} - -PAM_EXTERN int pam_sm_authenticate(pam_handle_t * pamh, int flags, - int argc, const char **argv) -{ - const char* user_name; - if (pam_get_user(pamh, &user_name, NULL) != PAM_SUCCESS) { - PAM_SYSLOG(pamh, LOG_INFO, "Could not get pam user."); - return PAM_PERM_DENIED; - } - - std::string str_user_name(user_name); - if (!ValidateUserName(user_name)) { - return PAM_PERM_DENIED; - } - - std::string response; - if (!(GetUser(str_user_name, &response))) { - return PAM_PERM_DENIED; - } - - // System accounts begin with the prefix `sa_`. - std::string sa_prefix = "sa_"; - if (str_user_name.compare(0, sa_prefix.size(), sa_prefix) == 0) { - return PAM_SUCCESS; - } - - std::string email; - if (!ParseJsonToEmail(response, &email) || email.empty()) { - return PAM_PERM_DENIED; - } - - response = ""; - if (!StartSession(email, &response)) { - PAM_SYSLOG(pamh, LOG_ERR, - "Bad response from the two-factor start session request: %s", - response.empty() ? "empty response" : response.c_str()); - return PAM_PERM_DENIED; - } - - std::string status; - if (!ParseJsonToKey(response, "status", &status)) { - PAM_SYSLOG(pamh, LOG_ERR, - "Failed to parse status from start session response"); - return PAM_PERM_DENIED; - } - - if (status == "NO_AVAILABLE_CHALLENGES") { - return PAM_SUCCESS; // User is not two-factor enabled. - } - - std::string session_id; - if (!ParseJsonToKey(response, "sessionId", &session_id)) { - return PAM_PERM_DENIED; - } - - std::vector<oslogin_utils::Challenge> challenges; - if (!ParseJsonToChallenges(response, &challenges)) { - PAM_SYSLOG(pamh, LOG_ERR, - "Failed to parse challenge values from JSON response"); - return PAM_PERM_DENIED; - } - - std::map<std::string,std::string> user_prompts; - user_prompts[AUTHZEN] = "Google phone prompt"; - user_prompts[TOTP] = "Security code from Google Authenticator application"; - user_prompts[INTERNAL_TWO_FACTOR] = "Security code from security key"; - user_prompts[IDV_PREREGISTERED_PHONE] = - "Voice or text message verification code"; - - oslogin_utils::Challenge challenge; - if (challenges.size() > 1) { - std::stringstream prompt; - prompt << "Available authentication methods: "; - for(vector<oslogin_utils::Challenge>::size_type i = 0; - i != challenges.size(); ++i) - prompt << "\n" << i+1 << ": " << user_prompts[challenges[i].type]; - prompt << "\n\nEnter a number: "; - - char *choice = NULL; - if (pam_prompt(pamh, PAM_PROMPT_ECHO_ON, &choice, "%s", - prompt.str().c_str()) != PAM_SUCCESS) { - pam_error(pamh, "Unable to get user input"); - } - - int choicei; - if (sscanf(choice, "%d", &choicei) == EOF) { - pam_error(pamh, "Unable to get user input"); - } - if (choicei > challenges.size()) { - pam_error(pamh, "Invalid option"); - } - challenge = challenges[choicei - 1]; - } else { - challenge = challenges[0]; - } - - if (challenge.status != "READY") { - // Call continueSession with the START_ALTERNATE flag. - if (!ContinueSession(true, email, "", session_id, challenge, &response)) { - PAM_SYSLOG(pamh, LOG_ERR, - "Bad response from two-factor continue session request: %s", - response.empty() ? "empty response" : response.c_str()); - return PAM_PERM_DENIED; - } - } - - char* user_token = NULL; - if (challenge.type == INTERNAL_TWO_FACTOR) { - if (pam_prompt(pamh, PAM_PROMPT_ECHO_ON, &user_token, - "Enter your security code: ") != PAM_SUCCESS) { - pam_error(pamh, "Unable to get user input"); - } - } else if (challenge.type == TOTP) { - if (pam_prompt(pamh, PAM_PROMPT_ECHO_ON, &user_token, - "Enter your one-time password: ") != PAM_SUCCESS) { - pam_error(pamh, "Unable to get user input"); - } - } else if (challenge.type == AUTHZEN) { - if (pam_prompt(pamh, PAM_PROMPT_ECHO_ON, &user_token, - "A login prompt has been sent to your enrolled device. " - "Press enter to continue") != PAM_SUCCESS) { - pam_error(pamh, "Unable to get user input"); - } - } else if (challenge.type == IDV_PREREGISTERED_PHONE) { - if (pam_prompt(pamh, PAM_PROMPT_ECHO_ON, &user_token, - "A security code has been sent to your phone. " - "Enter code to continue: ") != PAM_SUCCESS) { - pam_error(pamh, "Unable to get user input"); - } - } else { - PAM_SYSLOG(pamh, LOG_ERR, "Unsupported challenge type %s", - challenge.type.c_str()); - return PAM_PERM_DENIED; - } - - if (!ContinueSession(false, email, user_token, session_id, challenge, - &response)) { - PAM_SYSLOG(pamh, LOG_ERR, - "Bad response from two-factor continue session request: %s", - response.empty() ? "empty response" : response.c_str()); - return PAM_PERM_DENIED; - } - - if (!ParseJsonToKey(response, "status", &status) - || status != "AUTHENTICATED") { - return PAM_PERM_DENIED; - } - - return PAM_SUCCESS; -} -} diff --git a/packages/google-compute-engine-oslogin/src/utils.cc b/packages/google-compute-engine-oslogin/src/utils.cc deleted file mode 100644 index 0f05f6f..0000000 --- a/packages/google-compute-engine-oslogin/src/utils.cc +++ /dev/null @@ -1,864 +0,0 @@ -// Copyright 2017 Google Inc. All Rights Reserved. -// -// 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. - -// Requires libcurl4-openssl-dev libjson0 and libjson0-dev -#include <curl/curl.h> -#include <errno.h> -#include <grp.h> -#include <json.h> -#include <nss.h> -#include <stdio.h> -#include <time.h> - -#include <cstring> -#include <iostream> -#include <sstream> - -#if defined(__clang__) || __GNUC__ > 4 || \ - (__GNUC__ == 4 && \ - (__GNUC_MINOR__ > 9 || (__GNUC_MINOR__ == 9 && __GNUC_PATCHLEVEL__ > 0))) -#include <regex> -#define Regex std -#else -#include <boost/regex.hpp> -#define Regex boost -#endif - -#include <compat.h> -#include <oslogin_utils.h> - -using std::string; - -// Maximum number of retries for HTTP requests. -const int kMaxRetries = 1; - -// Regex for validating user names. -const char kUserNameRegex[] = "^[a-zA-Z0-9._][a-zA-Z0-9._-]{0,31}$"; - -namespace oslogin_utils { - -BufferManager::BufferManager(char* buf, size_t buflen) - : buf_(buf), buflen_(buflen) {} - -bool BufferManager::AppendString(const string& value, char** buffer, - int* errnop) { - size_t bytes_to_write = value.length() + 1; - *buffer = static_cast<char*>(Reserve(bytes_to_write, errnop)); - if (*buffer == NULL) { - return false; - } - strncpy(*buffer, value.c_str(), bytes_to_write); - return true; -} - -bool BufferManager::CheckSpaceAvailable(size_t bytes_to_write) const { - if (bytes_to_write > buflen_) { - return false; - } - return true; -} - -void* BufferManager::Reserve(size_t bytes, int* errnop) { - if (!CheckSpaceAvailable(bytes)) { - *errnop = ERANGE; - return NULL; - } - void* result = buf_; - buf_ += bytes; - buflen_ -= bytes; - return result; -} - -NssCache::NssCache(int cache_size) - : cache_size_(cache_size), - passwd_cache_(cache_size), - page_token_(""), - on_last_page_(false) {} - -void NssCache::Reset() { - page_token_ = ""; - index_ = 0; - passwd_cache_.clear(); - on_last_page_ = false; -} - -bool NssCache::HasNextPasswd() { - return (index_ < passwd_cache_.size()) && !passwd_cache_[index_].empty(); -} - -bool NssCache::GetNextPasswd(BufferManager* buf, passwd* result, int* errnop) { - if (!HasNextPasswd()) { - *errnop = ENOENT; - return false; - } - string cached_passwd = passwd_cache_[index_]; - bool success = ParseJsonToPasswd(cached_passwd, result, buf, errnop); - if (success) { - index_++; - } - return success; -} - -bool NssCache::LoadJsonArrayToCache(string response) { - Reset(); - json_object* root = NULL; - root = json_tokener_parse(response.c_str()); - if (root == NULL) { - return false; - } - // First grab the page token. - json_object* page_token_object; - if (json_object_object_get_ex(root, "nextPageToken", &page_token_object)) { - page_token_ = json_object_get_string(page_token_object); - } else { - // If the page token is not found, assume something went wrong. - page_token_ = ""; - on_last_page_ = true; - return false; - } - // A page_token of 0 means we are done. This response will not contain any - // login profiles. - if (page_token_ == "0") { - page_token_ = ""; - on_last_page_ = true; - return false; - } - // Now grab all of the loginProfiles. - json_object* login_profiles = NULL; - if (!json_object_object_get_ex(root, "loginProfiles", &login_profiles)) { - page_token_ = ""; - return false; - } - if (json_object_get_type(login_profiles) != json_type_array) { - return false; - } - int arraylen = json_object_array_length(login_profiles); - if (arraylen == 0 || arraylen > cache_size_) { - page_token_ = ""; - return false; - } - for (int i = 0; i < arraylen; i++) { - json_object* profile = json_object_array_get_idx(login_profiles, i); - passwd_cache_.push_back( - json_object_to_json_string_ext(profile, JSON_C_TO_STRING_PLAIN)); - } - return true; -} - -bool NssCache::NssGetpwentHelper(BufferManager* buf, struct passwd* result, - int* errnop) { - if (!HasNextPasswd() && !OnLastPage()) { - std::stringstream url; - url << kMetadataServerUrl << "users?pagesize=" << cache_size_; - string page_token = GetPageToken(); - if (!page_token.empty()) { - url << "&pagetoken=" << page_token; - } - string response; - long http_code = 0; - if (!HttpGet(url.str(), &response, &http_code) || http_code != 200 || - response.empty() || !LoadJsonArrayToCache(response)) { - // It is possible this to be true after LoadJsonArrayToCache(), so we - // must check it again. - if (!OnLastPage()) { - *errnop = ENOENT; - } - return false; - } - } - if (HasNextPasswd() && !GetNextPasswd(buf, result, errnop)) { - return false; - } - return true; -} - -size_t OnCurlWrite(void* buf, size_t size, size_t nmemb, void* userp) { - if (userp) { - std::ostream& os = *static_cast<std::ostream*>(userp); - std::streamsize len = size * nmemb; - if (os.write(static_cast<char*>(buf), len)) { - return len; - } - } - return 0; -} - -bool HttpDo(const string& url, const string& data, string* response, - long* http_code) { - if (response == NULL || http_code == NULL) { - return false; - } - CURLcode code(CURLE_FAILED_INIT); - curl_global_init(CURL_GLOBAL_ALL & ~CURL_GLOBAL_SSL); - CURL* curl = curl_easy_init(); - std::ostringstream response_stream; - int retry_count = 0; - if (curl) { - struct curl_slist* header_list = NULL; - header_list = curl_slist_append(header_list, "Metadata-Flavor: Google"); - if (header_list == NULL) { - curl_easy_cleanup(curl); - curl_global_cleanup(); - return false; - } - do { - response_stream.str(""); - response_stream.clear(); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &OnCurlWrite); - curl_easy_setopt(curl, CURLOPT_FILE, &response_stream); - curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5); - curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); - if (data != "") { - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str()); - } - - code = curl_easy_perform(curl); - if (code != CURLE_OK) { - curl_easy_cleanup(curl); - curl_global_cleanup(); - return false; - } - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, http_code); - } while (retry_count++ < kMaxRetries && *http_code == 500); - curl_slist_free_all(header_list); - } - *response = response_stream.str(); - curl_easy_cleanup(curl); - curl_global_cleanup(); - return true; -} - -bool HttpGet(const string& url, string* response, long* http_code) { - return HttpDo(url, "", response, http_code); -} - -bool HttpPost(const string& url, const string& data, string* response, - long* http_code) { - return HttpDo(url, data, response, http_code); -} - -bool ValidateUserName(const string& user_name) { - Regex::regex r(kUserNameRegex); - return Regex::regex_match(user_name, r); -} - -string UrlEncode(const string& param) { - CURL* curl = curl_easy_init(); - char* encoded = curl_easy_escape(curl, param.c_str(), param.length()); - if (encoded == NULL) { - curl_easy_cleanup(curl); - return ""; - } - string encoded_param = encoded; - curl_free(encoded); - curl_easy_cleanup(curl); - return encoded_param; -} - -bool ValidatePasswd(struct passwd* result, BufferManager* buf, int* errnop) { - // OS Login disallows uids less than 1000. - if (result->pw_uid < 1000) { - *errnop = EINVAL; - return false; - } - if (result->pw_gid == 0) { - *errnop = EINVAL; - return false; - } - if (strlen(result->pw_name) == 0) { - *errnop = EINVAL; - return false; - } - if (strlen(result->pw_dir) == 0) { - string home_dir = "/home/"; - home_dir.append(result->pw_name); - if (!buf->AppendString(home_dir, &result->pw_dir, errnop)) { - return false; - } - } - if (strlen(result->pw_shell) == 0) { - if (!buf->AppendString(DEFAULT_SHELL, &result->pw_shell, errnop)) { - return false; - } - } - - // OS Login does not utilize the passwd field and reserves the gecos field. - // Set these to be empty. - if (!buf->AppendString("", &result->pw_gecos, errnop)) { - return false; - } - if (!buf->AppendString("", &result->pw_passwd, errnop)) { - return false; - } - return true; -} - -bool ParseJsonToUsers(const string& json, std::vector<string>* result) { - json_object* root = NULL; - root = json_tokener_parse(json.c_str()); - if (root == NULL) { - return false; - } - - json_object* users = NULL; - if (!json_object_object_get_ex(root, "usernames", &users)) { - return false; - } - if (json_object_get_type(users) != json_type_array) { - return false; - } - for (int idx = 0; idx < json_object_array_length(users); idx++) { - json_object* user = json_object_array_get_idx(users, idx); - const char* username = json_object_get_string(user); - result->push_back(string(username)); - } - return true; -} - -bool ParseJsonToGroups(const string& json, std::vector<Group>* result) { - json_object* root = NULL; - root = json_tokener_parse(json.c_str()); - if (root == NULL) { - return false; - } - - json_object* groups = NULL; - if (!json_object_object_get_ex(root, "posixGroups", &groups)) { - return false; - } - if (json_object_get_type(groups) != json_type_array) { - return false; - } - for (int idx = 0; idx < json_object_array_length(groups); idx++) { - json_object* group = json_object_array_get_idx(groups, idx); - - json_object* gid; - if (!json_object_object_get_ex(group, "gid", &gid)) { - return false; - } - - json_object* name; - if (!json_object_object_get_ex(group, "name", &name)) { - return false; - } - - Group g; - g.gid = json_object_get_int64(gid); - // get_int64 will confusingly return 0 if the string can't be converted to - // an integer. We can't rely on type check as it may be a string in the API. - if (g.gid == 0) { - return false; - } - g.name = json_object_get_string(name); - if (g.name == "") { - return false; - } - - result->push_back(g); - } - return true; -} - -std::vector<string> ParseJsonToSshKeys(const string& json) { - std::vector<string> result; - json_object* root = NULL; - root = json_tokener_parse(json.c_str()); - if (root == NULL) { - return result; - } - // Locate the sshPublicKeys object. - json_object* login_profiles = NULL; - if (!json_object_object_get_ex(root, "loginProfiles", &login_profiles)) { - return result; - } - if (json_object_get_type(login_profiles) != json_type_array) { - return result; - } - login_profiles = json_object_array_get_idx(login_profiles, 0); - - json_object* ssh_public_keys = NULL; - if (!json_object_object_get_ex(login_profiles, "sshPublicKeys", - &ssh_public_keys)) { - return result; - } - - if (json_object_get_type(ssh_public_keys) != json_type_object) { - return result; - } - json_object_object_foreach(ssh_public_keys, key, obj) { - (void)(key); - if (json_object_get_type(obj) != json_type_object) { - continue; - } - string key_to_add = ""; - bool expired = false; - json_object_object_foreach(obj, key, val) { - string string_key(key); - int val_type = json_object_get_type(val); - if (string_key == "key") { - if (val_type != json_type_string) { - continue; - } - key_to_add = (char*)json_object_get_string(val); - } - if (string_key == "expirationTimeUsec") { - if (val_type == json_type_int || val_type == json_type_string) { - uint64_t expiry_usec = (uint64_t)json_object_get_int64(val); - struct timeval tp; - gettimeofday(&tp, NULL); - uint64_t cur_usec = tp.tv_sec * 1000000 + tp.tv_usec; - expired = cur_usec > expiry_usec; - } else { - continue; - } - } - } - if (!key_to_add.empty() && !expired) { - result.push_back(key_to_add); - } - } - return result; -} - -bool ParseJsonToPasswd(const string& json, struct passwd* result, - BufferManager* buf, int* errnop) { - json_object* root = NULL; - root = json_tokener_parse(json.c_str()); - if (root == NULL) { - *errnop = ENOENT; - return false; - } - json_object* login_profiles = NULL; - // If this is called from getpwent_r, loginProfiles won't be in the response. - if (json_object_object_get_ex(root, "loginProfiles", &login_profiles)) { - if (json_object_get_type(login_profiles) != json_type_array) { - return false; - } - root = login_profiles; - root = json_object_array_get_idx(root, 0); - } - // Locate the posixAccounts object. - json_object* posix_accounts = NULL; - if (!json_object_object_get_ex(root, "posixAccounts", &posix_accounts)) { - *errnop = ENOENT; - return false; - } - if (json_object_get_type(posix_accounts) != json_type_array) { - return false; - } - posix_accounts = json_object_array_get_idx(posix_accounts, 0); - - // Populate with some default values that ValidatePasswd can detect if they - // are not set. - result->pw_uid = 0; - result->pw_shell = (char*)""; - result->pw_name = (char*)""; - result->pw_dir = (char*)""; - - // Iterate through the json response and populate the passwd struct. - if (json_object_get_type(posix_accounts) != json_type_object) { - return false; - } - json_object_object_foreach(posix_accounts, key, val) { - int val_type = json_object_get_type(val); - // Convert char* to c++ string for easier comparison. - string string_key(key); - - if (string_key == "uid") { - if (val_type == json_type_int || val_type == json_type_string) { - result->pw_uid = (uint32_t)json_object_get_int64(val); - if (result->pw_uid == 0) { - *errnop = EINVAL; - return false; - } - } else { - *errnop = EINVAL; - return false; - } - } else if (string_key == "gid") { - if (val_type == json_type_int || val_type == json_type_string) { - result->pw_gid = (uint32_t)json_object_get_int64(val); - // Use the uid as the default group when gid is not set or is zero. - if (result->pw_gid == 0) { - result->pw_gid = result->pw_uid; - } - } else { - *errnop = EINVAL; - return false; - } - } else if (string_key == "username") { - if (val_type != json_type_string) { - *errnop = EINVAL; - return false; - } - if (!buf->AppendString((char*)json_object_get_string(val), - &result->pw_name, errnop)) { - return false; - } - } else if (string_key == "homeDirectory") { - if (val_type != json_type_string) { - *errnop = EINVAL; - return false; - } - if (!buf->AppendString((char*)json_object_get_string(val), - &result->pw_dir, errnop)) { - return false; - } - } else if (string_key == "shell") { - if (val_type != json_type_string) { - *errnop = EINVAL; - return false; - } - if (!buf->AppendString((char*)json_object_get_string(val), - &result->pw_shell, errnop)) { - return false; - } - } - } - - return ValidatePasswd(result, buf, errnop); -} - -bool AddUsersToGroup(std::vector<string> users, struct group* result, - BufferManager* buf, int* errnop) { - if (users.size() < 1) { - return true; - } - - // Get some space for the char* array for number of users + 1 for NULL cap. - char** bufp; - if (!(bufp = - (char**)buf->Reserve(sizeof(char*) * (users.size() + 1), errnop))) { - return false; - } - result->gr_mem = bufp; - - for (int i = 0; i < (int) users.size(); i++) { - if (!buf->AppendString(users[i], bufp, errnop)) { - result->gr_mem = NULL; - return false; - } - } - *bufp = NULL; // End the array with a null pointer. - - return true; -} - -bool ParseJsonToEmail(const string& json, string* email) { - json_object* root = NULL; - root = json_tokener_parse(json.c_str()); - if (root == NULL) { - return false; - } - // Locate the email object. - json_object* login_profiles = NULL; - if (!json_object_object_get_ex(root, "loginProfiles", &login_profiles)) { - return false; - } - if (json_object_get_type(login_profiles) != json_type_array) { - return false; - } - login_profiles = json_object_array_get_idx(login_profiles, 0); - json_object* json_email = NULL; - if (!json_object_object_get_ex(login_profiles, "name", &json_email)) { - return false; - } - - *email = json_object_get_string(json_email); - return true; -} - -bool ParseJsonToSuccess(const string& json) { - json_object* root = NULL; - root = json_tokener_parse(json.c_str()); - if (root == NULL) { - return false; - } - json_object* success = NULL; - if (!json_object_object_get_ex(root, "success", &success)) { - return false; - } - return (bool)json_object_get_boolean(success); -} - -bool ParseJsonToKey(const string& json, const string& key, string* response) { - json_object* root = NULL; - json_object* json_response = NULL; - const char* c_response; - - root = json_tokener_parse(json.c_str()); - if (root == NULL) { - return false; - } - - if (!json_object_object_get_ex(root, key.c_str(), &json_response)) { - return false; - } - - if (!(c_response = json_object_get_string(json_response))) { - return false; - } - - *response = c_response; - return true; -} - -bool ParseJsonToChallenges(const string& json, - std::vector<Challenge>* challenges) { - json_object* root = NULL; - - root = json_tokener_parse(json.c_str()); - if (root == NULL) { - return false; - } - - json_object* jsonChallenges = NULL; - if (!json_object_object_get_ex(root, "challenges", &jsonChallenges)) { - return false; - } - - json_object *challengeId, *challengeType, *challengeStatus = NULL; - for (int i = 0; i < json_object_array_length(jsonChallenges); ++i) { - if (!json_object_object_get_ex(json_object_array_get_idx(jsonChallenges, i), - "challengeId", &challengeId)) { - return false; - } - if (!json_object_object_get_ex(json_object_array_get_idx(jsonChallenges, i), - "challengeType", &challengeType)) { - return false; - } - if (!json_object_object_get_ex(json_object_array_get_idx(jsonChallenges, i), - "status", &challengeStatus)) { - return false; - } - Challenge challenge; - challenge.id = json_object_get_int(challengeId); - challenge.type = json_object_get_string(challengeType); - challenge.status = json_object_get_string(challengeStatus); - - challenges->push_back(challenge); - } - - return true; -} - -bool FindGroup(struct group* result, BufferManager* buf, int* errnop) { - if (result->gr_name == NULL && result->gr_gid == 0) { - return false; - } - std::stringstream url; - std::vector<Group> groups; - - string response; - long http_code; - string pageToken = ""; - - do { - url.str(""); - url << kMetadataServerUrl << "groups"; - if (pageToken != "") url << "?pageToken=" << pageToken; - - response.clear(); - http_code = 0; - if (!HttpGet(url.str(), &response, &http_code) || http_code != 200 || - response.empty()) { - *errnop = EAGAIN; - return false; - } - - if (!ParseJsonToKey(response, "nextPageToken", &pageToken)) { - pageToken = ""; - } - - groups.clear(); - if (!ParseJsonToGroups(response, &groups) || groups.empty()) { - *errnop = ENOENT; - return false; - } - - // Check for a match. - for (int i = 0; i < (int) groups.size(); i++) { - Group el = groups[i]; - if ((result->gr_name != NULL) && (string(result->gr_name) == el.name)) { - // Set the name even though it matches because the final string must - // be stored in the provided buffer. - if (!buf->AppendString(el.name, &result->gr_name, errnop)) { - return false; - } - result->gr_gid = el.gid; - return true; - } - if ((result->gr_gid != 0) && (result->gr_gid == el.gid)) { - if (!buf->AppendString(el.name, &result->gr_name, errnop)) { - return false; - } - return true; - } - } - } while (pageToken != ""); - // Not found. - *errnop = ENOENT; - return false; -} - -bool GetGroupsForUser(string username, std::vector<Group>* groups, - int* errnop) { - std::stringstream url; - - string response; - long http_code; - string pageToken = ""; - - do { - url.str(""); - url << kMetadataServerUrl << "groups?username=" << username; - if (pageToken != "") url << "?pageToken=" << pageToken; - - response.clear(); - http_code = 0; - if (!HttpGet(url.str(), &response, &http_code) || http_code != 200 || - response.empty()) { - *errnop = EAGAIN; - return false; - } - - if (!ParseJsonToKey(response, "pageToken", &pageToken)) { - pageToken = ""; - } - - if (!ParseJsonToGroups(response, groups)) { - *errnop = ENOENT; - return false; - } - } while (pageToken != ""); - return true; -} - -bool GetUsersForGroup(string groupname, std::vector<string>* users, - int* errnop) { - string response; - long http_code; - string pageToken = ""; - std::stringstream url; - - do { - url.str(""); - url << kMetadataServerUrl << "users?groupname=" << groupname; - if (pageToken != "") url << "?pageToken=" << pageToken; - - response.clear(); - http_code = 0; - if (!HttpGet(url.str(), &response, &http_code) || http_code != 200 || - response.empty()) { - *errnop = EAGAIN; - return false; - } - if (!ParseJsonToKey(response, "nextPageToken", &pageToken)) { - pageToken = ""; - } - if (!ParseJsonToUsers(response, users)) { - *errnop = EINVAL; - return false; - } - } while (pageToken != ""); - return true; -} - -bool GetUser(const string& username, string* response) { - std::stringstream url; - url << kMetadataServerUrl << "users?username=" << UrlEncode(username); - - long http_code = 0; - if (!HttpGet(url.str(), response, &http_code) || response->empty() || - http_code != 200) { - return false; - } - return true; -} - -bool StartSession(const string& email, string* response) { - bool ret = true; - struct json_object *jobj, *jarr; - - jarr = json_object_new_array(); - json_object_array_add(jarr, json_object_new_string(INTERNAL_TWO_FACTOR)); - json_object_array_add(jarr, json_object_new_string(AUTHZEN)); - json_object_array_add(jarr, json_object_new_string(TOTP)); - json_object_array_add(jarr, json_object_new_string(IDV_PREREGISTERED_PHONE)); - - jobj = json_object_new_object(); - json_object_object_add(jobj, "email", json_object_new_string(email.c_str())); - json_object_object_add(jobj, "supportedChallengeTypes", jarr); // Ownership transferred to jobj. - - const char* data; - data = json_object_to_json_string_ext(jobj, JSON_C_TO_STRING_PLAIN); - - std::stringstream url; - url << kMetadataServerUrl << "authenticate/sessions/start"; - - long http_code = 0; - if (!HttpPost(url.str(), data, response, &http_code) || response->empty() || - http_code != 200) { - ret = false; - } - - json_object_put(jobj); - - return ret; -} - -bool ContinueSession(bool alt, const string& email, const string& user_token, - const string& session_id, const Challenge& challenge, - string* response) { - bool ret = true; - struct json_object *jobj, *jresp; - - jobj = json_object_new_object(); - json_object_object_add(jobj, "email", json_object_new_string(email.c_str())); - json_object_object_add(jobj, "challengeId", - json_object_new_int(challenge.id)); - - if (alt) { - json_object_object_add(jobj, "action", - json_object_new_string("START_ALTERNATE")); - } else { - json_object_object_add(jobj, "action", json_object_new_string("RESPOND")); - } - - // AUTHZEN type and START_ALTERNATE action don't provide credentials. - if (challenge.type != AUTHZEN && !alt) { - jresp = json_object_new_object(); - json_object_object_add(jresp, "credential", - json_object_new_string(user_token.c_str())); - json_object_object_add(jobj, "proposalResponse", jresp); // Ownership transferred to jobj. - } - - const char* data = NULL; - data = json_object_to_json_string_ext(jobj, JSON_C_TO_STRING_PLAIN); - - std::stringstream url; - url << kMetadataServerUrl << "authenticate/sessions/" << session_id - << "/continue"; - long http_code = 0; - if (!HttpPost(url.str(), data, response, &http_code) || response->empty() || - http_code != 200) { - ret = false; - } - - json_object_put(jobj); - - return ret; -} -} // namespace oslogin_utils |