blob: 6d427262efcecc36771611f0f99254aa26b33470 [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:
97 show_usage ( );
98 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 )
117 error_msg_and_die ( "user %s does not exist", opt_username );
118
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;
130 pw-> pw_name = xstrdup ( pw-> pw_name );
131 pw-> pw_dir = xstrdup ( pw-> pw_dir );
132 pw-> pw_shell = xstrdup ( pw-> pw_shell );
133
134 if (( getuid ( ) == 0 ) || correct_password ( pw ))
135 log_su ( pw, 1 );
136 else {
137 log_su ( pw, 0 );
138 error_msg_and_die ( "incorrect password" );
139 }
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 )
155 opt_shell = xstrdup ( pw-> pw_shell );
156
157 change_identity ( pw );
158 setup_environment ( opt_shell, opt_loginshell, !opt_preserve, pw );
Eric Andersen27f64e12002-06-23 04:24:25 +0000159 run_shell ( opt_shell, opt_loginshell, opt_command, (const char**)opt_args );
Robert Griebl1fca5582002-06-04 20:45:46 +0000160
161 return EXIT_FAILURE;
162}