1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2  *
3  * Copyright (C) 2005-2006 William Jon McCann <mccann@jhu.edu>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA
18  * 02110-1335, USA.
19  *
20  * Authors: William Jon McCann <mccann@jhu.edu>
21  *
22  */
23 
24 #include "config.h"
25 
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/time.h>
29 #include <sys/types.h>
30 #include <sys/wait.h>
31 #include <termios.h>
32 
33 #include <glib/gi18n.h>
34 #include <gtk/gtk.h>
35 
36 #include "cs-auth.h"
37 #include "setuid.h"
38 
39 /* Initializations that potentially take place as a privileged user:
40    If the executable is setuid root, then these initializations
41    are run as root, before discarding privileges.
42 */
43 static gboolean
privileged_initialization(void)44 privileged_initialization (void)
45 {
46         gboolean ret;
47         char    *nolock_reason;
48         char    *orig_uid;
49         char    *uid_message;
50 
51 #ifndef NO_LOCKING
52         /* before hack_uid () for proper permissions */
53         cs_auth_priv_init ();
54 #endif /* NO_LOCKING */
55 
56         ret = hack_uid (&nolock_reason,
57                         &orig_uid,
58                         &uid_message);
59         if (nolock_reason) {
60                 g_warning ("Locking disabled: %s", nolock_reason);
61         }
62         if (uid_message && cs_auth_get_verbose ()) {
63                 g_print ("Modified UID: %s", uid_message);
64         }
65 
66         g_free (nolock_reason);
67         g_free (orig_uid);
68         g_free (uid_message);
69 
70         return ret;
71 }
72 
73 
74 /* Figure out what locking mechanisms are supported.
75  */
76 static gboolean
lock_initialization(char ** nolock_reason)77 lock_initialization (char **nolock_reason)
78 {
79         if (nolock_reason) {
80                 *nolock_reason = NULL;
81         }
82 
83 #ifdef NO_LOCKING
84         if (nolock_reason) {
85                 *nolock_reason = g_strdup ("not compiled with locking support");
86         }
87         return FALSE;
88 #else /* !NO_LOCKING */
89 
90         /* Finish initializing locking, now that we're out of privileged code. */
91         if (! cs_auth_init ()) {
92                 if (nolock_reason) {
93                         *nolock_reason = g_strdup ("error getting password");
94                 }
95                 return FALSE;
96         }
97 
98         /* If locking is currently enabled, but the environment indicates that
99            we have been launched as MDM's "Background" program, then disable
100            locking just in case.
101         */
102         if (getenv ("RUNNING_UNDER_MDM")) {
103                 if (nolock_reason) {
104                         *nolock_reason = g_strdup ("running under MDM");
105                 }
106                 return FALSE;
107         }
108 
109         /* If the server is XDarwin (MacOS X) then disable locking.
110            (X grabs only affect X programs, so you can use Command-Tab
111            to bring any other Mac program to the front, e.g., Terminal.)
112         */
113         {
114                 gboolean macos = FALSE;
115 
116 #ifdef __APPLE__
117                 /* Disable locking if *running* on Apple hardware, since we have no
118                    reliable way to determine whether the server is running on MacOS.
119                    Hopefully __APPLE__ means "MacOS" and not "Linux on Mac hardware"
120                    but I'm not really sure about that.
121                 */
122                 macos = TRUE;
123 #endif
124 
125                 if (macos) {
126                         if (nolock_reason) {
127                                 *nolock_reason = g_strdup ("Cannot lock securely on MacOS X");
128                         }
129                         return FALSE;
130                 }
131         }
132 
133 #endif /* NO_LOCKING */
134 
135         return TRUE;
136 }
137 
138 static char *
request_password(const char * prompt)139 request_password (const char *prompt)
140 {
141         char           buf [255];
142         char          *pass;
143         char          *password;
144         struct termios ts0;
145         struct termios ts1;
146 
147         tcgetattr (fileno (stdin), &ts0);
148         ts1 = ts0;
149         ts1.c_lflag &= ~ECHO;
150 
151         printf ("%s", prompt);
152 
153         if (tcsetattr (fileno (stdin), TCSAFLUSH, &ts1) != 0) {
154                 fprintf (stderr, "Could not set terminal attributes\n");
155                 exit (1);
156         }
157 
158         pass = fgets (buf, sizeof (buf) - 1, stdin);
159 
160         tcsetattr (fileno (stdin), TCSANOW, &ts0);
161 
162         if (!pass || !*pass) {
163                 exit (0);
164         }
165 
166         if (pass [strlen (pass) - 1] == '\n') {
167                 pass [strlen (pass) - 1] = 0;
168         }
169 
170         password = g_strdup (pass);
171 
172         memset (pass, '\b', strlen (pass));
173 
174         return password;
175 }
176 
177 static gboolean
auth_message_handler(CsAuthMessageStyle style,const char * msg,char ** response,gpointer data)178 auth_message_handler (CsAuthMessageStyle style,
179                       const char        *msg,
180                       char             **response,
181                       gpointer           data)
182 {
183         gboolean ret;
184 
185         g_message ("Got message style %d: '%s'", style, msg);
186 
187         ret = TRUE;
188 
189         switch (style) {
190         case CS_AUTH_MESSAGE_PROMPT_ECHO_ON:
191                 break;
192         case CS_AUTH_MESSAGE_PROMPT_ECHO_OFF:
193                 {
194                         char *password;
195                         password = request_password (msg);
196                         *response = password;
197                 }
198                 break;
199         case CS_AUTH_MESSAGE_ERROR_MSG:
200                 break;
201         case CS_AUTH_MESSAGE_TEXT_INFO:
202                 break;
203         default:
204                 g_assert_not_reached ();
205         }
206 
207         return ret;
208 }
209 
210 int
main(int argc,char ** argv)211 main (int    argc,
212       char **argv)
213 {
214         GError         *error         = NULL;
215         gboolean        verbose       = TRUE;
216         char           *nolock_reason = NULL;
217 
218 #ifdef ENABLE_NLS
219         bindtextdomain (GETTEXT_PACKAGE, "/usr/local/share/locale");
220 # ifdef HAVE_BIND_TEXTDOMAIN_CODESET
221         bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
222 # endif
223         textdomain (GETTEXT_PACKAGE);
224 #endif
225 
226         cs_auth_set_verbose (verbose);
227         if (! privileged_initialization ()) {
228                 exit (1);
229         }
230 
231         if (! gtk_init_with_args (&argc, &argv, NULL, NULL, NULL, &error)) {
232                 fprintf (stderr, "%s", error->message);
233                 g_error_free (error);
234                 exit (1);
235         }
236 
237         if (! lock_initialization (&nolock_reason)) {
238                 if (nolock_reason) {
239                         g_warning ("Screen locking disabled: %s", nolock_reason);
240                         g_free (nolock_reason);
241                 }
242 
243                 exit (1);
244         }
245 
246  again:
247         error = NULL;
248 
249         if (cs_auth_verify_user (g_get_user_name (), g_getenv ("DISPLAY"), auth_message_handler, NULL, &error)) {
250                 printf ("Correct!\n");
251         } else {
252                 if (error != NULL) {
253                         fprintf (stderr, "ERROR: %s\n", error->message);
254                         g_error_free (error);
255                 }
256                 printf ("Incorrect\n");
257                 goto again;
258         }
259 
260 	return 0;
261 }
262