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