xref: /haiku/src/bin/multiuser/su.cpp (revision 4bd0c1066b227cec4b79883bdef697c7a27f2e90)
1 /*
2  * Copyright 2017, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Axel Dörfler, axeld@pinc-software.de
7  *		Augustin Cavalier <waddlesplash>
8  */
9 
10 
11 #include <SupportDefs.h>
12 
13 #include <errno.h>
14 #include <pwd.h>
15 #include <signal.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <syslog.h>
20 #include <termios.h>
21 #include <unistd.h>
22 
23 #include "multiuser_utils.h"
24 
25 
26 extern const char* __progname;
27 const char* kProgramName = __progname;
28 
29 const uint32 kRetries = 3;
30 
31 
32 static void
33 usage()
34 {
35 	fprintf(stderr, "usage: %s [-pl] [-c command] [username]\n", kProgramName);
36 	exit(1);
37 }
38 
39 
40 int
41 main(int argc, char *argv[])
42 {
43 	bool loginShell = false;
44 	const char* command = NULL;
45 
46 	char c;
47 	while ((c = getopt(argc, argv, "c:l")) != -1) {
48 		switch (c) {
49 			case 'l':
50 				loginShell = true;
51 				break;
52 
53 			case 'c':
54 				command = optarg;
55 				break;
56 
57 			default:
58 				usage();
59 				break;
60 		}
61 	}
62 
63 	argc -= optind;
64 	argv += optind;
65 
66 	const char* user = NULL;
67 	if (argc > 0)
68 		user = argv[0];
69 
70 	if (user == NULL)
71 		user = "user";
72 		// aka 'root' on Haiku
73 
74 	// login
75 
76 	openlog(kProgramName, 0, LOG_AUTH);
77 
78 	status_t status = B_ERROR;
79 	struct passwd* passwd = NULL;
80 
81 	status = authenticate_user("password: ", user, &passwd, NULL,
82 		kRetries, false);
83 
84 	if (status < B_OK || !passwd) {
85 		if (passwd != NULL)
86 			syslog(LOG_NOTICE, "su failed for \"%s\"", passwd->pw_name);
87 		else
88 			syslog(LOG_NOTICE, "su attempt for non-existent user \"%s\"", user);
89 		exit(1);
90 	}
91 
92 	// setup environment for the user
93 
94 	status = setup_environment(passwd, true, false);
95 	if (status < B_OK) {
96 		// refused login
97 		fprintf(stderr, "%s: Refused login. Setting up environment failed: %s\n",
98 			kProgramName, strerror(status));
99 		syslog(LOG_NOTICE, "su refused for \"%s\"", passwd->pw_name);
100 		exit(1);
101 	}
102 
103 	syslog(LOG_INFO, "su as \"%s\"", passwd->pw_name);
104 
105 	// start shell
106 	const char* args[] = {getenv("SHELL"), NULL, NULL, NULL, NULL};
107 	int nextarg = 1;
108 	if (loginShell) {
109 		args[nextarg++] = "-login";
110 	}
111 	if (command != NULL) {
112 		args[nextarg++] = "-c";
113 		args[nextarg++] = command;
114 	}
115 
116 	execv(args[0], (char **)args);
117 
118 	// try default shell
119 	args[0] = "/bin/sh";
120 	execv(args[0], (char **)args);
121 
122 	fprintf(stderr, "%s: starting the shell failed: %s", kProgramName,
123 		strerror(errno));
124 
125 	return 1;
126 }
127 
128