Initialize Tizen 2.3
[external/shadow-utils.git] / src / sulogin.c
1 /*
2  * Copyright (c) 1989 - 1994, Julianne Frances Haugh
3  * Copyright (c) 1996 - 2000, Marek Michałkiewicz
4  * Copyright (c) 2002 - 2006, Tomasz Kłoczko
5  * Copyright (c) 2007 - 2008, Nicolas François
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the copyright holders or contributors may not be used to
17  *    endorse or promote products derived from this software without
18  *    specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include <config.h>
34
35 #ident "$Id: sulogin.c 2851 2009-04-30 21:39:38Z nekral-guest $"
36
37 #include <fcntl.h>
38 #include <pwd.h>
39 #include <signal.h>
40 #include <stdio.h>
41 #include <sys/ioctl.h>
42 #include "defines.h"
43 #include "getdef.h"
44 #include "prototypes.h"
45 #include "pwauth.h"
46 /*@-exitarg@*/
47 #include "exitcodes.h"
48
49 /*
50  * Global variables
51  */
52 static char name[BUFSIZ];
53 static char pass[BUFSIZ];
54
55 static struct passwd pwent;
56
57 extern char **newenvp;
58 extern size_t newenvc;
59
60 extern char **environ;
61
62 #ifndef ALARM
63 #define ALARM   60
64 #endif
65
66 /* local function prototypes */
67 static RETSIGTYPE catch_signals (int);
68
69 static RETSIGTYPE catch_signals (unused int sig)
70 {
71         exit (1);
72 }
73
74 /*
75  * syslogd is usually not running at the time when sulogin is typically
76  * called, cluttering the screen with unnecessary messages. Suggested by
77  * Ivan Nejgebauer <ian@unsux.ns.ac.yu>.  --marekm
78  */
79 #undef USE_SYSLOG
80
81  /*ARGSUSED*/ int main (int argc, char **argv)
82 {
83         char *cp;
84         char **envp = environ;
85         TERMIO termio;
86         int err = 0;
87
88 #ifdef  USE_TERMIO
89         ioctl (0, TCGETA, &termio);
90         termio.c_iflag |= (ICRNL | IXON);
91         termio.c_oflag |= (OPOST | ONLCR);
92         termio.c_cflag |= (CREAD);
93         termio.c_lflag |= (ISIG | ICANON | ECHO | ECHOE | ECHOK);
94         ioctl (0, TCSETAF, &termio);
95 #endif
96 #ifdef  USE_TERMIOS
97         tcgetattr (0, &termio);
98         termio.c_iflag |= (ICRNL | IXON);
99         termio.c_oflag |= (CREAD);
100         termio.c_lflag |= (ECHO | ECHOE | ECHOK | ICANON | ISIG);
101         tcsetattr (0, TCSANOW, &termio);
102 #endif
103
104         (void) setlocale (LC_ALL, "");
105         (void) bindtextdomain (PACKAGE, LOCALEDIR);
106         (void) textdomain (PACKAGE);
107
108 #ifdef  USE_SYSLOG
109         OPENLOG ("sulogin");
110 #endif
111         initenv ();
112         if (argc > 1) {
113                 close (0);
114                 close (1);
115                 close (2);
116
117                 if (open (argv[1], O_RDWR) >= 0) {
118                         dup (0);
119                         dup (0);
120                 } else {
121 #ifdef  USE_SYSLOG
122                         SYSLOG (LOG_WARN, "cannot open %s\n", argv[1]);
123                         closelog ();
124 #endif
125                         exit (1);
126                 }
127         }
128         if (access (PASSWD_FILE, F_OK) == -1) { /* must be a password file! */
129                 puts (_("No password file"));
130 #ifdef  USE_SYSLOG
131                 SYSLOG (LOG_WARN, "No password file\n");
132                 closelog ();
133 #endif
134                 exit (1);
135         }
136 #if !defined(DEBUG) && defined(SULOGIN_ONLY_INIT)
137         if (getppid () != 1) {  /* parent must be INIT */
138 #ifdef  USE_SYSLOG
139                 SYSLOG (LOG_WARN, "Pid == %d, not 1\n", getppid ());
140                 closelog ();
141 #endif
142                 exit (1);
143         }
144 #endif
145         if ((isatty (0) == 0) || (isatty (1) == 0) || (isatty (2) == 0)) {
146 #ifdef  USE_SYSLOG
147                 closelog ();
148 #endif
149                 exit (1);       /* must be a terminal */
150         }
151         /* If we were init, we need to start a new session */
152         if (getppid() == 1) {
153                 setsid();
154                 if (ioctl(0, TIOCSCTTY, 1) != 0) {
155                         fputs (_("TIOCSCTTY failed"), stderr);
156                 }
157         }
158         while (NULL != *envp) {         /* add inherited environment, */
159                 addenv (*envp, NULL);   /* some variables change later */
160                 envp++;
161         }
162
163 #ifndef USE_PAM
164
165         cp = getdef_str ("ENV_TZ");
166         if (NULL != cp) {
167                 addenv (('/' == *cp) ? tz (cp) : cp, NULL);
168         }
169         cp = getdef_str ("ENV_HZ");
170         if (NULL != cp) {
171                 addenv (cp, NULL);      /* set the default $HZ, if one */
172         }
173 #endif                          /* !USE_PAM */
174
175         (void) strcpy (name, "root");   /* KLUDGE!!! */
176
177         (void) signal (SIGALRM, catch_signals); /* exit if the timer expires */
178         (void) alarm (ALARM);           /* only wait so long ... */
179
180         while (true) {          /* repeatedly get login/password pairs */
181                 pw_entry (name, &pwent);        /* get entry from password file */
182                 if (pwent.pw_name == (char *) 0) {
183                         /*
184                          * Fail secure
185                          */
186                         puts (_("No password entry for 'root'"));
187 #ifdef  USE_SYSLOG
188                         SYSLOG (LOG_WARN, "No password entry for 'root'\n");
189                         closelog ();
190 #endif
191                         exit (1);
192                 }
193
194                 /*
195                  * Here we prompt for the root password, or if no password
196                  * is given we just exit.
197                  */
198
199                 /* get a password for root */
200                 cp = getpass (_
201                               ("\n"
202                                "Type control-d to proceed with normal startup,\n"
203                                "(or give root password for system maintenance):"));
204                 /*
205                  * XXX - can't enter single user mode if root password is
206                  * empty.  I think this doesn't happen very often :-). But
207                  * it will work with standard getpass() (no NULL on EOF). 
208                  * --marekm
209                  */
210                 if ((NULL == cp) || ('\0' == *cp)) {
211 #ifdef  USE_SYSLOG
212                         SYSLOG (LOG_INFO, "Normal startup\n");
213                         closelog ();
214 #endif
215                         puts ("");
216 #ifdef  TELINIT
217                         execl (PATH_TELINIT, "telinit", RUNLEVEL, (char *) 0);
218 #endif
219                         exit (0);
220                 } else {
221                         STRFCPY (pass, cp);
222                         strzero (cp);
223                 }
224                 if (valid (pass, &pwent)) {     /* check encrypted passwords ... */
225                         break;  /* ... encrypted passwords matched */
226                 }
227
228 #ifdef  USE_SYSLOG
229                 SYSLOG (LOG_WARN, "Incorrect root password\n");
230 #endif
231                 sleep (2);
232                 puts (_("Login incorrect"));
233         }
234         strzero (pass);
235         (void) alarm (0);
236         (void) signal (SIGALRM, SIG_DFL);
237         environ = newenvp;      /* make new environment active */
238
239         puts (_("Entering System Maintenance Mode"));
240 #ifdef  USE_SYSLOG
241         SYSLOG (LOG_INFO, "System Maintenance Mode\n");
242 #endif
243
244 #ifdef  USE_SYSLOG
245         closelog ();
246 #endif
247         /* exec the shell finally. */
248         err = shell (pwent.pw_shell, (char *) 0, environ);
249
250         return ((err == ENOENT) ? E_CMD_NOTFOUND : E_CMD_NOEXEC);
251 }
252