Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1237)

Side by Side Diff: remoting/host/linux/remoting_user_session.cc

Issue 2939263003: Add support for CRD user-session to operate setuid (Closed)
Patch Set: Allow support to CRD user_session to operate setuid Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 // 4 //
5 // This file implements a wrapper to run the virtual me2me session within a 5 // This file implements a wrapper to run the virtual me2me session within a
6 // proper PAM session. It will generally be run as root and drop privileges to 6 // proper PAM session. It will generally be run as root and drop privileges to
7 // the specified user before running the me2me session script. 7 // the specified user before running the me2me session script.
8 8
9 #include <sys/types.h> 9 #include <sys/types.h>
10 #include <sys/stat.h> 10 #include <sys/stat.h>
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after
238 238
239 private: 239 private:
240 pam_handle_t* pam_handle_ = nullptr; 240 pam_handle_t* pam_handle_ = nullptr;
241 int last_return_code_ = PAM_SUCCESS; 241 int last_return_code_ = PAM_SUCCESS;
242 242
243 DISALLOW_COPY_AND_ASSIGN(PamHandle); 243 DISALLOW_COPY_AND_ASSIGN(PamHandle);
244 }; 244 };
245 245
246 // Runs the me2me script in a PAM session. Exits the program on failure. 246 // Runs the me2me script in a PAM session. Exits the program on failure.
247 // If chown_log is true, the owner and group of the file associated with stdout 247 // If chown_log is true, the owner and group of the file associated with stdout
248 // will be changed to the target user. 248 // will be changed to the target user. If match_uid is not nullopt, this
249 void ExecuteSession(std::string user, base::StringPiece script_path, 249 // function will fail if the final user id does not match the one provided.
250 bool chown_log) { 250 void ExecuteSession(std::string user,
251 base::StringPiece script_path,
252 bool chown_log,
253 base::Optional<uid_t> match_uid) {
251 ////////////////////////////////////////////////////////////////////////////// 254 //////////////////////////////////////////////////////////////////////////////
252 // Set up the PAM session 255 // Set up the PAM session
253 ////////////////////////////////////////////////////////////////////////////// 256 //////////////////////////////////////////////////////////////////////////////
254 257
255 PamHandle pam_handle(kPamName, user.c_str(), &kPamConversation); 258 PamHandle pam_handle(kPamName, user.c_str(), &kPamConversation);
256 CHECK(pam_handle.IsInitialized()) << "Failed to initialize PAM"; 259 CHECK(pam_handle.IsInitialized()) << "Failed to initialize PAM";
257 260
258 // Make sure the account is valid and enabled. 261 // Make sure the account is valid and enabled.
259 pam_handle.CheckReturnCode(pam_handle.AccountManagement(0), "Account check"); 262 pam_handle.CheckReturnCode(pam_handle.AccountManagement(0), "Account check");
260 263
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
308 311
309 private: 312 private:
310 struct passwd* pwinfo_; 313 struct passwd* pwinfo_;
311 }; 314 };
312 315
313 // Fetch pwinfo again, as it may have been invalidated or the user name might 316 // Fetch pwinfo again, as it may have been invalidated or the user name might
314 // have been remapped. 317 // have been remapped.
315 pwinfo = getpwnam(user.c_str()); 318 pwinfo = getpwnam(user.c_str());
316 PCHECK(pwinfo != nullptr) << "getpwnam failed"; 319 PCHECK(pwinfo != nullptr) << "getpwnam failed";
317 320
321 if (match_uid && pwinfo->pw_uid != *match_uid) {
322 LOG(FATAL) << "PAM remapped username to one with a different user ID.";
323 }
324
318 if (chown_log) { 325 if (chown_log) {
319 int result = fchown(STDOUT_FILENO, pwinfo->pw_uid, pwinfo->pw_gid); 326 int result = fchown(STDOUT_FILENO, pwinfo->pw_uid, pwinfo->pw_gid);
320 PLOG_IF(WARNING, result != 0) << "Failed to change log file owner"; 327 PLOG_IF(WARNING, result != 0) << "Failed to change log file owner";
321 } 328 }
322 329
323 PreExecDelegate pre_exec_delegate(pwinfo); 330 PreExecDelegate pre_exec_delegate(pwinfo);
324 331
325 base::LaunchOptions launch_options; 332 base::LaunchOptions launch_options;
326 333
327 // Required to allow suid binaries to function in the session. 334 // Required to allow suid binaries to function in the session.
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
391 (std::size_t) 0); 398 (std::size_t) 0);
392 399
393 mode_t mode = umask(0177); 400 mode_t mode = umask(0177);
394 int fd = mkstemp(logfile); 401 int fd = mkstemp(logfile);
395 PCHECK(fd != -1); 402 PCHECK(fd != -1);
396 umask(mode); 403 umask(mode);
397 404
398 return fd; 405 return fd;
399 } 406 }
400 407
408 // Find the username for the current user. If either USER or LOGNAME is set to
409 // a user matching our real user id, we return that. Otherwise, we use getpwuid
410 // to attempt a reverse lookup. Note: It's possible to more than user with the
411 // same user id but different group membership, home directories, et cetera,
412 // which is why we check USER and LOGNAME first.
413 std::string FindCurrentUsername() {
414 uid_t real_id = getuid();
415 struct passwd* pwinfo;
416 for (const char* var : {"USER", "LOGNAME"}) {
417 const char* value = getenv(var);
418 if (value) {
419 pwinfo = getpwnam(value);
420 // USER and LOGNAME can be overridden, so make sure the value is valid
421 // and matches the UID of the invoking user.
422 if (pwinfo && pwinfo->pw_uid == real_id) {
423 return pwinfo->pw_name;
424 }
425 }
426 }
427 errno = 0;
428 pwinfo = getpwuid(real_id);
429 PCHECK(pwinfo) << "getpwuid failed";
430 return pwinfo->pw_name;
431 }
432
401 // Daemonizes the process. Output is redirected to a file. Exits the program on 433 // Daemonizes the process. Output is redirected to a file. Exits the program on
402 // failure. 434 // failure.
403 // 435 //
404 // This logic is mostly the same as daemonize() in linux_me2me_host.py. Log- 436 // This logic is mostly the same as daemonize() in linux_me2me_host.py. Log-
405 // file redirection especially should be kept in sync. Note that this does 437 // file redirection especially should be kept in sync. Note that this does
406 // not currently wait for the host to start successfully before exiting the 438 // not currently wait for the host to start successfully before exiting the
407 // parent process like the Python script does, as that functionality is 439 // parent process like the Python script does, as that functionality is
408 // probably not useful at boot, where the wrapper is expected to be used. If 440 // probably not useful at boot, where the wrapper is expected to be used. If
409 // it turns out to be desired, it can be implemented by setting up a pipe and 441 // it turns out to be desired, it can be implemented by setting up a pipe and
410 // passing a file descriptor to the Python script. 442 // passing a file descriptor to the Python script.
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
467 base::FilePath script_path = 499 base::FilePath script_path =
468 command_line->GetSwitchValuePath(kScriptSwitchName); 500 command_line->GetSwitchValuePath(kScriptSwitchName);
469 std::string user = command_line->GetSwitchValueNative(kUserSwitchName); 501 std::string user = command_line->GetSwitchValueNative(kUserSwitchName);
470 bool foreground = command_line->HasSwitch(kForegroundSwitchName); 502 bool foreground = command_line->HasSwitch(kForegroundSwitchName);
471 503
472 if (script_path.empty()) { 504 if (script_path.empty()) {
473 std::fputs("The path to the me2me python script is required.\n", stderr); 505 std::fputs("The path to the me2me python script is required.\n", stderr);
474 std::exit(EXIT_FAILURE); 506 std::exit(EXIT_FAILURE);
475 } 507 }
476 508
509 uid_t real_uid = getuid();
Jamie 2017/06/16 19:24:23 Please be consistent with the naming of this; real
rkjnsn 2017/06/16 20:28:31 Good catch.
510
511 if (real_uid == 0 && user.empty()) {
512 std::fputs("Target user must be specified when run as root.\n", stderr);
513 std::exit(EXIT_FAILURE);
514 } else if (real_uid != 0 && !user.empty()) {
515 std::fputs("Target user may not be specified by non-root users.\n", stderr);
516 std::exit(EXIT_FAILURE);
Jamie 2017/06/16 19:24:23 Since you already check LOGNAME and USER and use t
rkjnsn 2017/06/16 20:28:31 user-session isn't really intended to be called di
517 }
518
477 if (user.empty()) { 519 if (user.empty()) {
478 std::fputs("The target user must be specified.\n", stderr); 520 user = FindCurrentUsername();
479 std::exit(EXIT_FAILURE);
480 } 521 }
481 522
482 if (!foreground) { 523 if (!foreground) {
483 Daemonize(); 524 Daemonize();
484 } 525 }
485 526
486 ExecuteSession(std::move(user), script_path.value(), !foreground); 527 ExecuteSession(std::move(user), script_path.value(), !foreground,
528 real_uid != 0 ? base::make_optional(real_uid) : base::nullopt);
487 } 529 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698