blob: 85f5cbe7b5088850c934f8964ea2f2382ee9051e [file] [log] [blame]
Robert Griebl1fca5582002-06-04 20:45:46 +00001/* vi: set sw=4 ts=4: */
2
Robert Griebl1fca5582002-06-04 20:45:46 +00003#include <fcntl.h>
4#include <signal.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8#include <syslog.h>
9#include <termios.h>
10#include <unistd.h>
11#include <utmp.h>
12#include <sys/resource.h>
13#include <sys/stat.h>
14#include <sys/time.h>
15#include <sys/types.h>
16#include <ctype.h>
17#include <time.h>
18
Eric Andersen27f64e12002-06-23 04:24:25 +000019#include "busybox.h"
Robert Griebl1fca5582002-06-04 20:45:46 +000020
21
22
23/* The shell to run if none is given in the user's passwd entry. */
24#define DEFAULT_SHELL "/bin/sh"
25#define DEFAULT_USER "root"
26
27//#define SYSLOG_SUCCESS
28#define SYSLOG_FAILURE
29
30
31#if defined( SYSLOG_SUCCESS ) || defined( SYSLOG_FAILURE )
32/* Log the fact that someone has run su to the user given by PW;
33 if SUCCESSFUL is nonzero, they gave the correct password, etc. */
34
35static void log_su ( const struct passwd *pw, int successful )
36{
37 const char *old_user, *tty;
38
39#if !defined( SYSLOG_SUCESS )
40 if ( successful )
41 return;
42#endif
43#if !defined( SYSLOG_FAILURE )
44 if ( !successful )
45 return;
46#endif
47
48 if ( pw-> pw_uid ) // not to root -> ignored
49 return;
50
51 /* The utmp entry (via getlogin) is probably the best way to identify
52 the user, especially if someone su's from a su-shell. */
53 old_user = getlogin ( );
54 if ( !old_user ) {
55 /* getlogin can fail -- usually due to lack of utmp entry. Resort to getpwuid. */
56 struct passwd *pwd = getpwuid ( getuid ( ));
57 old_user = ( pwd ? pwd-> pw_name : "" );
58 }
59
60 tty = ttyname ( 2 );
61
62 openlog ( "su", 0, LOG_AUTH );
63 syslog ( LOG_NOTICE, "%s%s on %s", successful ? "" : "FAILED SU ", old_user, tty ? tty : "none" );
64}
65#endif
66
67
68
69int su_main ( int argc, char **argv )
70{
71 int flag;
72 int opt_preserve = 0;
73 int opt_loginshell = 0;
74 char *opt_shell = 0;
75 char *opt_command = 0;
76 char *opt_username = DEFAULT_USER;
77 char **opt_args = 0;
78 struct passwd *pw, pw_copy;
79
80
81 while (( flag = getopt ( argc, argv, "c:lmps:" )) != -1 ) {
82 switch ( flag ) {
83 case 'c':
84 opt_command = optarg;
85 break;
86 case 'm':
87 case 'p':
88 opt_preserve = 1;
89 break;
90 case 's':
91 opt_shell = optarg;
92 break;
93 case 'l':
94 opt_loginshell = 1;
95 break;
96 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +000097 bb_show_usage( );
Robert Griebl1fca5582002-06-04 20:45:46 +000098 break;
99 }
100 }
101
102 if (( optind < argc ) && ( argv [optind][0] == '-' ) && ( argv [optind][1] == 0 )) {
103 opt_loginshell = 1;
104 ++optind;
105 }
106
107 /* get user if specified */
108 if ( optind < argc )
109 opt_username = argv [optind++];
110
111 if ( optind < argc )
112 opt_args = argv + optind;
113
114
115 pw = getpwnam ( opt_username );
116 if ( !pw )
Manuel Novoa III cad53642003-03-19 09:13:01 +0000117 bb_error_msg_and_die ( "user %s does not exist", opt_username );
Robert Griebl1fca5582002-06-04 20:45:46 +0000118
119 /* Make sure pw->pw_shell is non-NULL. It may be NULL when NEW_USER
120 is a username that is retrieved via NIS (YP), but that doesn't have
121 a default shell listed. */
122 if ( !pw-> pw_shell || !pw->pw_shell [0] )
123 pw-> pw_shell = (char *) DEFAULT_SHELL;
124
125 /* Make a copy of the password information and point pw at the local
126 copy instead. Otherwise, some systems (e.g. Linux) would clobber
127 the static data through the getlogin call from log_su. */
128 pw_copy = *pw;
129 pw = &pw_copy;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000130 pw-> pw_name = bb_xstrdup ( pw-> pw_name );
131 pw-> pw_dir = bb_xstrdup ( pw-> pw_dir );
132 pw-> pw_shell = bb_xstrdup ( pw-> pw_shell );
Robert Griebl1fca5582002-06-04 20:45:46 +0000133
134 if (( getuid ( ) == 0 ) || correct_password ( pw ))
135 log_su ( pw, 1 );
136 else {
137 log_su ( pw, 0 );
Manuel Novoa III cad53642003-03-19 09:13:01 +0000138 bb_error_msg_and_die ( "incorrect password" );
Robert Griebl1fca5582002-06-04 20:45:46 +0000139 }
140
141 if ( !opt_shell && opt_preserve )
142 opt_shell = getenv ( "SHELL" );
143
144 if ( opt_shell && getuid ( ) && restricted_shell ( pw-> pw_shell ))
145 {
146 /* The user being su'd to has a nonstandard shell, and so is
147 probably a uucp account or has restricted access. Don't
148 compromise the account by allowing access with a standard
149 shell. */
150 fputs ( "using restricted shell\n", stderr );
151 opt_shell = 0;
152 }
153
154 if ( !opt_shell )
Manuel Novoa III cad53642003-03-19 09:13:01 +0000155 opt_shell = bb_xstrdup ( pw-> pw_shell );
Robert Griebl1fca5582002-06-04 20:45:46 +0000156
157 change_identity ( pw );
158 setup_environment ( opt_shell, opt_loginshell, !opt_preserve, pw );
Eric Andersen9e480452003-07-03 10:07:04 +0000159 run_shell ( opt_shell, opt_loginshell, opt_command, (const char**)opt_args
160#ifdef CONFIG_SELINUX
161 , 0
162#endif
163 );
Robert Griebl1fca5582002-06-04 20:45:46 +0000164
165 return EXIT_FAILURE;
166}