multiuser: New implementation of su.

We're still using the (now-deprecated) coreutils su, so this is
a replacement for that. It functions almost equivalently,
and supports the major arguments (-l, -c).

(Note that login/su to a non-root user is presently busted, though.
See #13583.)
This commit is contained in:
Augustin Cavalier 2017-07-23 11:04:06 -04:00
parent eed40cb8c5
commit 95295296cd
3 changed files with 132 additions and 2 deletions

View File

@ -256,7 +256,7 @@ SubInclude HAIKU_TOP src bin bfs_tools ;
SubInclude HAIKU_TOP src bin cddb_lookup ;
SubInclude HAIKU_TOP src bin compress ;
SubInclude HAIKU_TOP src bin consoled ;
SubInclude HAIKU_TOP src bin coreutils ;
#SubInclude HAIKU_TOP src bin coreutils ;
SubInclude HAIKU_TOP src bin desklink ;
SubInclude HAIKU_TOP src bin fwcontrol ;
SubInclude HAIKU_TOP src bin hid_decode ;

View File

@ -11,6 +11,8 @@ StaticLibrary libmultiuser_utils.a : multiuser_utils.cpp ;
BinCommand login : login.cpp : libmultiuser_utils.a ;
BinCommand su : su.cpp : libmultiuser_utils.a ;
BinCommand passwd : passwd.cpp : libmultiuser_utils.a ;
BinCommand useradd : useradd.cpp ;
@ -23,5 +25,6 @@ BinCommand groupdel : groupdel.cpp ;
BinCommand groupmod : groupmod.cpp : [ TargetLibstdc++ ] ;
# set set-uid bit on passwd
# set set-uid bit on passwd, su
MODE on passwd = 04755 ;
MODE on su = 04755 ;

127
src/bin/multiuser/su.cpp Normal file
View File

@ -0,0 +1,127 @@
/*
* Copyright 2017, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, axeld@pinc-software.de
* Augustin Cavalier <waddlesplash>
*/
#include <SupportDefs.h>
#include <errno.h>
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <termios.h>
#include <unistd.h>
#include "multiuser_utils.h"
extern const char* __progname;
const char* kProgramName = __progname;
const uint32 kRetries = 3;
static void
usage()
{
fprintf(stderr, "usage: %s [-pl] [-c command] [username]\n", kProgramName);
exit(1);
}
int
main(int argc, char *argv[])
{
bool loginShell = false;
const char* command = NULL;
char c;
while ((c = getopt(argc, argv, "c:l")) != -1) {
switch (c) {
case 'l':
loginShell = true;
break;
case 'c':
command = optarg;
break;
default:
usage();
break;
}
}
argc -= optind;
argv += optind;
const char* user = NULL;
if (argc > 0)
user = argv[0];
if (user == NULL)
user = "user";
// aka 'root' on Haiku
// login
openlog(kProgramName, 0, LOG_AUTH);
status_t status = B_ERROR;
struct passwd* passwd = NULL;
status = authenticate_user("password: ", user, &passwd, NULL,
kRetries, false);
if (status < B_OK || !passwd) {
if (passwd != NULL)
syslog(LOG_NOTICE, "su failed for \"%s\"", passwd->pw_name);
else
syslog(LOG_NOTICE, "su attempt for non-existent user \"%s\"", user);
exit(1);
}
// setup environment for the user
status = setup_environment(passwd, true, false);
if (status < B_OK) {
// refused login
fprintf(stderr, "%s: Refused login. Setting up environment failed: %s\n",
kProgramName, strerror(status));
syslog(LOG_NOTICE, "su refused for \"%s\"", passwd->pw_name);
exit(1);
}
syslog(LOG_INFO, "su as \"%s\"", passwd->pw_name);
// start shell
const char* args[] = {getenv("SHELL"), NULL, NULL, NULL, NULL};
int nextarg = 1;
if (loginShell) {
args[nextarg++] = "-login";
}
if (command != NULL) {
args[nextarg++] = "-c";
args[nextarg++] = command;
}
execv(args[0], (char **)args);
// try default shell
args[0] = "/bin/sh";
execv(args[0], (char **)args);
fprintf(stderr, "%s: starting the shell failed: %s", kProgramName,
strerror(errno));
return 1;
}