1 /*
2  * Gksu -- a library providing access to su functionality
3  * Copyright (C) 2004-2009 Gustavo Noronha Silva
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <fcntl.h>
26 #include <pwd.h>
27 #include <sys/ioctl.h>
28 #include <sys/types.h>
29 #include <sys/wait.h>
30 #include <sys/stat.h>
31 #include <sys/select.h>
32 #include <errno.h>
33 #include <termios.h>
34 #include <libutil.h>
35 
36 #include <glibtop.h>
37 #include <glibtop/procstate.h>
38 
39 #include <gdk/gdk.h>
40 #include <gdk/gdkx.h>
41 
42 #define SN_API_NOT_YET_FROZEN
43 #include <libsn/sn.h>
44 
45 #include <gtk/gtk.h>
46 #include <locale.h>
47 
48 #include <gconf/gconf-client.h>
49 #include <gnome-keyring.h>
50 
51 #include "defines.h"
52 #include "../config.h"
53 
54 #include "libgksu.h"
55 #include "../libgksuui/gksuui-dialog.h"
56 
57 static void
58 gksu_context_launch_complete (GksuContext *context);
59 
60 GType
gksu_error_get_type(void)61 gksu_error_get_type (void)
62 {
63   static GType etype = 0;
64   if (etype == 0) {
65     static const GEnumValue values[] = {
66       { GKSU_ERROR_HELPER, "GKSU_ERROR_HELPER", "helper" },
67       { GKSU_ERROR_NOCOMMAND, "GKSU_ERROR_NOCOMMAND", "nocommand" },
68       { GKSU_ERROR_NOPASSWORD, "GKSU_ERROR_NOPASSWORD", "nopassword" },
69       { GKSU_ERROR_FORK, "GKSU_ERROR_FORK", "fork" },
70       { GKSU_ERROR_EXEC, "GKSU_ERROR_EXEC", "exec" },
71       { GKSU_ERROR_PIPE, "GKSU_ERROR_PIPE", "pipe" },
72       { GKSU_ERROR_PIPEREAD, "GKSU_ERROR_PIPEREAD", "piperead" },
73       { GKSU_ERROR_WRONGPASS, "GKSU_ERROR_WRONGPASS", "wrongpass" },
74       { GKSU_ERROR_CHILDFAILED, "GKSU_ERROR_CHILDFAILED", "childfailed" },
75       { GKSU_ERROR_CANCELED, "GKSU_ERROR_CANCELED", "canceled" },
76       { GKSU_ERROR_WRONGAUTOPASS, "GKSU_ERROR_WRONGAUTOPASS", "wrongautopass" },
77       { 0, NULL, NULL }
78     };
79     etype = g_enum_register_static ("GksuError", values);
80   }
81   return etype;
82 }
83 
84 static pid_t
test_lock(const char * fname)85 test_lock(const char* fname)
86 {
87    int FD = open(fname, 0);
88    if(FD < 0) {
89       if(errno == ENOENT) {
90 	 // File does not exist
91 	 return 0;
92       } else {
93 	 perror("open");
94 	 return(-1);
95       }
96    }
97    struct flock fl;
98    fl.l_type = F_WRLCK;
99    fl.l_whence = SEEK_SET;
100    fl.l_start = 0;
101    fl.l_len = 0;
102    if (fcntl(FD, F_GETLK, &fl) < 0) {
103       g_critical("fcntl error");
104       close(FD);
105       return(-1);
106    }
107    close(FD);
108    // lock is available
109    if(fl.l_type == F_UNLCK)
110       return(0);
111    // file is locked by another process
112    return (fl.l_pid);
113 }
114 
115 static int
get_lock(const char * File)116 get_lock(const char *File)
117 {
118    int FD = open(File,O_RDWR | O_CREAT | O_TRUNC,0640);
119    if (FD < 0)
120    {
121       // Read only .. cant have locking problems there.
122       if (errno == EROFS)
123       {
124 	 g_warning(_("Not using locking for read only lock file %s"),File);
125 	 return dup(0);       // Need something for the caller to close
126       }
127 
128       // Feh.. We do this to distinguish the lock vs open case..
129       errno = EPERM;
130       return -1;
131    }
132    fcntl(FD,F_SETFD, FD_CLOEXEC);
133 
134    // Aquire a write lock
135    struct flock fl;
136    fl.l_type = F_WRLCK;
137    fl.l_whence = SEEK_SET;
138    fl.l_start = 0;
139    fl.l_len = 0;
140    if (fcntl(FD,F_SETLK,&fl) == -1)
141    {
142       if (errno == ENOLCK)
143       {
144 	 g_warning(_("Not using locking for nfs mounted lock file %s"), File);
145 	 unlink(File);
146 	 close(FD);
147 	 return dup(0);       // Need something for the caller to close
148       }
149 
150       int Tmp = errno;
151       close(FD);
152       errno = Tmp;
153       return -1;
154    }
155 
156    return FD;
157 }
158 
159 /*
160  * code 'stolen' from gnome-session's logout.c
161  *
162  * Written by Owen Taylor <otaylor@redhat.com>
163  * Copyright (C) Red Hat
164  */
165 typedef struct {
166   GdkScreen    *screen;
167   int           monitor;
168   GdkRectangle  area;
169   int           rowstride;
170   GdkWindow    *root_window;
171   GdkWindow    *draw_window;
172   GdkPixbuf    *start_pb, *end_pb, *frame;
173   guchar       *start_p, *end_p, *frame_p;
174   GTimeVal      start_time;
175   GdkGC        *gc;
176 } FadeoutData;
177 
178 FadeoutData *fade_data = NULL;
179 static GList *fadeout_windows = NULL;
180 
181 #define FADE_DURATION 500.0
182 
183 int
gsm_screen_get_width(GdkScreen * screen,int monitor)184 gsm_screen_get_width (GdkScreen *screen,
185 		      int        monitor)
186 {
187 	GdkRectangle geometry;
188 
189 	gdk_screen_get_monitor_geometry (screen, monitor, &geometry);
190 
191 	return geometry.width;
192 }
193 
194 int
gsm_screen_get_height(GdkScreen * screen,int monitor)195 gsm_screen_get_height (GdkScreen *screen,
196 		       int        monitor)
197 {
198 	GdkRectangle geometry;
199 
200 	gdk_screen_get_monitor_geometry (screen, monitor, &geometry);
201 
202 	return geometry.height;
203 }
204 
205 int
gsm_screen_get_x(GdkScreen * screen,int monitor)206 gsm_screen_get_x (GdkScreen *screen,
207 		  int        monitor)
208 {
209 	GdkRectangle geometry;
210 
211 	gdk_screen_get_monitor_geometry (screen, monitor, &geometry);
212 
213 	return geometry.x;
214 }
215 
216 int
gsm_screen_get_y(GdkScreen * screen,int monitor)217 gsm_screen_get_y (GdkScreen *screen,
218 		  int        monitor)
219 {
220 	GdkRectangle geometry;
221 
222 	gdk_screen_get_monitor_geometry (screen, monitor, &geometry);
223 
224 	return geometry.y;
225 }
226 
227 static void
get_current_frame(FadeoutData * fadeout,double sat)228 get_current_frame (FadeoutData *fadeout,
229 		   double    sat)
230 {
231   guchar *sp, *ep, *fp;
232   int i, j, width, offset;
233 
234   width = fadeout->area.width * 3;
235   offset = 0;
236 
237   for (i = 0; i < fadeout->area.height; i++)
238     {
239       sp = fadeout->start_p + offset;
240       ep = fadeout->end_p   + offset;
241       fp = fadeout->frame_p + offset;
242 
243       for (j = 0; j < width; j += 3)
244 	{
245 	  guchar r = abs (*(sp++) - ep[0]);
246 	  guchar g = abs (*(sp++) - ep[1]);
247 	  guchar b = abs (*(sp++) - ep[2]);
248 
249 	  *(fp++) = *(ep++) + r * sat;
250 	  *(fp++) = *(ep++) + g * sat;
251 	  *(fp++) = *(ep++) + b * sat;
252 	}
253 
254       offset += fadeout->rowstride;
255     }
256 }
257 
258 static void
darken_pixbuf(GdkPixbuf * pb)259 darken_pixbuf (GdkPixbuf *pb)
260 {
261   int width, height, rowstride;
262   int i, j;
263   guchar *p, *pixels;
264 
265   width     = gdk_pixbuf_get_width (pb) * 3;
266   height    = gdk_pixbuf_get_height (pb);
267   rowstride = gdk_pixbuf_get_rowstride (pb);
268   pixels    = gdk_pixbuf_get_pixels (pb);
269 
270   for (i = 0; i < height; i++)
271     {
272       p = pixels + (i * rowstride);
273       for (j = 0; j < width; j++)
274 	p [j] >>= 1;
275     }
276 }
277 
278 static gboolean
fadeout_callback(FadeoutData * fadeout)279 fadeout_callback (FadeoutData *fadeout)
280 {
281   GTimeVal current_time;
282   double elapsed, percent;
283 
284   g_get_current_time (&current_time);
285   elapsed = ((((double)current_time.tv_sec - fadeout->start_time.tv_sec) * G_USEC_PER_SEC +
286 	      (current_time.tv_usec - fadeout->start_time.tv_usec))) / 1000.0;
287 
288   if (elapsed < 0)
289     {
290       g_warning ("System clock seemed to go backwards?");
291       elapsed = G_MAXDOUBLE;
292     }
293 
294   if (elapsed > FADE_DURATION)
295     {
296       gdk_draw_pixbuf (fadeout->draw_window,
297 		       fadeout->gc,
298 		       fadeout->end_pb,
299 		       0, 0,
300 		       0, 0,
301 		       fadeout->area.width,
302 		       fadeout->area.height,
303 		       GDK_RGB_DITHER_NONE,
304 		       0, 0);
305 
306       return FALSE;
307     }
308 
309   percent = elapsed / FADE_DURATION;
310 
311   get_current_frame (fadeout, 1.0 - percent);
312   gdk_draw_pixbuf (fadeout->draw_window,
313 		   fadeout->gc,
314 		   fadeout->frame,
315 		   0, 0,
316 		   0, 0,
317 		   fadeout->area.width,
318 		   fadeout->area.height,
319 		   GDK_RGB_DITHER_NONE,
320 		   0, 0);
321 
322   gdk_flush ();
323 
324   return TRUE;
325 }
326 
327 static void
hide_fadeout_windows(void)328 hide_fadeout_windows (void)
329 {
330   GList *l;
331 
332   for (l = fadeout_windows; l; l = l->next)
333     {
334       gdk_window_hide (GDK_WINDOW (l->data));
335       g_object_unref (l->data);
336     }
337 
338   g_list_free (fadeout_windows);
339   fadeout_windows = NULL;
340 }
341 
342 static gboolean
fadein_callback(FadeoutData * fadeout)343 fadein_callback (FadeoutData *fadeout)
344 {
345   GTimeVal current_time;
346   double elapsed, percent;
347 
348   g_get_current_time (&current_time);
349   elapsed = ((((double)current_time.tv_sec - fadeout->start_time.tv_sec) * G_USEC_PER_SEC +
350 	      (current_time.tv_usec - fadeout->start_time.tv_usec))) / 1000.0;
351 
352   if (elapsed < 0)
353     {
354       g_warning ("System clock seemed to go backwards?");
355       elapsed = G_MAXDOUBLE;
356     }
357 
358   if (elapsed > FADE_DURATION)
359     {
360       gdk_draw_pixbuf (fadeout->draw_window,
361 		       fadeout->gc,
362 		       fadeout->end_pb,
363 		       0, 0,
364 		       0, 0,
365 		       fadeout->area.width,
366 		       fadeout->area.height,
367 		       GDK_RGB_DITHER_NONE,
368 		       0, 0);
369 
370       g_object_unref (fadeout->gc);
371       g_object_unref (fadeout->start_pb);
372       g_object_unref (fadeout->end_pb);
373       g_object_unref (fadeout->frame);
374 
375       g_free (fadeout);
376 
377       hide_fadeout_windows ();
378 
379       return FALSE;
380     }
381 
382   percent = elapsed / FADE_DURATION;
383 
384   get_current_frame (fadeout, percent);
385   gdk_draw_pixbuf (fadeout->draw_window,
386 		   fadeout->gc,
387 		   fadeout->frame,
388 		   0, 0,
389 		   0, 0,
390 		   fadeout->area.width,
391 		   fadeout->area.height,
392 		   GDK_RGB_DITHER_NONE,
393 		   0, 0);
394 
395   gdk_flush ();
396 
397   return TRUE;
398 }
399 
400 static void
fadeout_screen(GdkScreen * screen,int monitor)401 fadeout_screen (GdkScreen *screen,
402 		int        monitor)
403 {
404   GdkWindowAttr attr;
405   int attr_mask;
406   GdkGCValues values;
407   FadeoutData *fadeout;
408 
409   fadeout = g_new (FadeoutData, 1);
410 
411   fadeout->screen = screen;
412   fadeout->monitor = monitor;
413 
414   fadeout->area.x = gsm_screen_get_x (screen, monitor);
415   fadeout->area.y = gsm_screen_get_y (screen, monitor);
416   fadeout->area.width = gsm_screen_get_width (screen, monitor);
417   fadeout->area.height = gsm_screen_get_height (screen, monitor);
418 
419   fadeout->root_window = gdk_screen_get_root_window (screen);
420   attr.window_type = GDK_WINDOW_CHILD;
421   attr.x = fadeout->area.x;
422   attr.y = fadeout->area.y;
423   attr.width = fadeout->area.width;
424   attr.height = fadeout->area.height;
425   attr.wclass = GDK_INPUT_OUTPUT;
426   attr.visual = gdk_screen_get_system_visual (fadeout->screen);
427   attr.colormap = gdk_screen_get_default_colormap (fadeout->screen);
428   attr.override_redirect = TRUE;
429   attr_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP | GDK_WA_NOREDIR;
430 
431   fadeout->draw_window = gdk_window_new (fadeout->root_window, &attr, attr_mask);
432   fadeout_windows = g_list_prepend (fadeout_windows, fadeout->draw_window);
433 
434   fadeout->start_pb = gdk_pixbuf_get_from_drawable (NULL,
435 						    fadeout->root_window,
436 						    NULL,
437 						    fadeout->area.x,
438 						    fadeout->area.y,
439 						    0, 0,
440 						    fadeout->area.width,
441 						    fadeout->area.height);
442 
443   fadeout->end_pb = gdk_pixbuf_copy (fadeout->start_pb);
444   darken_pixbuf (fadeout->end_pb);
445 
446   fadeout->frame = gdk_pixbuf_copy (fadeout->start_pb);
447   fadeout->rowstride = gdk_pixbuf_get_rowstride (fadeout->start_pb);
448 
449   fadeout->start_p = gdk_pixbuf_get_pixels (fadeout->start_pb);
450   fadeout->end_p   = gdk_pixbuf_get_pixels (fadeout->end_pb);
451   fadeout->frame_p = gdk_pixbuf_get_pixels (fadeout->frame);
452 
453   values.subwindow_mode = GDK_INCLUDE_INFERIORS;
454 
455   fadeout->gc = gdk_gc_new_with_values (fadeout->root_window, &values, GDK_GC_SUBWINDOW);
456 
457   gdk_window_set_back_pixmap (fadeout->draw_window, NULL, FALSE);
458   gdk_window_show (fadeout->draw_window);
459   gdk_draw_pixbuf (fadeout->draw_window,
460 		   fadeout->gc,
461 		   fadeout->frame,
462 		   0, 0,
463 		   0, 0,
464 		   fadeout->area.width,
465 		   fadeout->area.height,
466 		   GDK_RGB_DITHER_NONE,
467 		   0, 0);
468 
469   g_get_current_time (&fadeout->start_time);
470   g_idle_add ((GSourceFunc) fadeout_callback, fadeout);
471 
472   fade_data = fadeout;
473 }
474 
475 /* End of 'stolen' code */
476 
477 #define GRAB_TRIES	16
478 #define GRAB_WAIT	250 /* milliseconds */
479 
480 typedef enum
481   {
482     FAILED_GRAB_MOUSE,
483     FAILED_GRAB_KEYBOARD
484   } FailedGrabWhat;
485 
486 void
report_failed_grab(FailedGrabWhat what)487 report_failed_grab (FailedGrabWhat what)
488 {
489   GtkWidget *dialog;
490 
491   dialog = g_object_new (GTK_TYPE_MESSAGE_DIALOG,
492 			 "message-type", GTK_MESSAGE_WARNING,
493 			 "buttons", GTK_BUTTONS_CLOSE,
494 			 NULL);
495 
496   switch (what)
497     {
498     case FAILED_GRAB_MOUSE:
499       gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG(dialog),
500 				     _("<b><big>Could not grab your mouse.</big></b>"
501 				       "\n\n"
502 				       "A malicious client may be eavesdropping "
503 				       "on your session or you may have just clicked "
504 				       "a menu or some application just decided to get "
505 				       "focus."
506 				       "\n\n"
507 				       "Try again."));
508 
509       break;
510     case FAILED_GRAB_KEYBOARD:
511       gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG(dialog),
512 				     _("<b><big>Could not grab your keyboard.</big></b>"
513 				       "\n\n"
514 				       "A malicious client may be eavesdropping "
515 				       "on your session or you may have just clicked "
516 				       "a menu or some application just decided to get "
517 				       "focus."
518 				       "\n\n"
519 				       "Try again."));
520       break;
521     }
522 
523   gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE);
524   gtk_dialog_run (GTK_DIALOG(dialog));
525   gtk_widget_destroy (dialog);
526 
527   while (gtk_events_pending ())
528     gtk_main_iteration ();
529 
530 }
531 
532 int
grab_keyboard_and_mouse(GtkWidget * dialog)533 grab_keyboard_and_mouse (GtkWidget *dialog)
534 {
535   GdkGrabStatus status;
536   gint grab_tries = 0;
537   gint lock = -1;
538   pid_t pid;
539 
540   gchar *fname = g_strdup (getenv ("GKSU_LOCK_FILE"));
541   if (fname == NULL)
542     fname = g_strdup_printf ("%s/.gksu.lock", getenv ("HOME"));
543 
544   pid = test_lock (fname);
545 
546   if (pid != 0)
547     {
548       g_warning ("Lock taken by pid: %i. Exiting.", pid);
549       exit (0);
550     }
551 
552   lock = get_lock(fname);
553   if( lock < 0)
554     g_warning ("Unable to create lock file.");
555   g_free (fname);
556 
557   gdk_threads_enter ();
558   fadeout_screen (gdk_screen_get_default (), 0);
559   gtk_widget_show_all (dialog);
560 
561   /* reset cursor */
562   gdk_window_set_cursor(dialog->window, gdk_cursor_new(GDK_LEFT_PTR));
563 
564   for(;;)
565     {
566       status = gdk_pointer_grab ((GTK_WIDGET(dialog))->window, TRUE, 0, NULL,
567 				 NULL, GDK_CURRENT_TIME);
568       if (status == GDK_GRAB_SUCCESS)
569 	break;
570       usleep (GRAB_WAIT * 1000);
571       if (++grab_tries > GRAB_TRIES)
572 	{
573 	  gtk_widget_hide (dialog);
574 	  g_get_current_time (&fade_data->start_time);
575 	  while (fadein_callback (fade_data) != FALSE);
576 	  report_failed_grab (FAILED_GRAB_MOUSE);
577 	  exit (1);
578 	  break;
579 	}
580     }
581 
582   for(;;)
583     {
584       status = gdk_keyboard_grab ((GTK_WIDGET(dialog))->window,
585 				  FALSE, GDK_CURRENT_TIME);
586       if (status == GDK_GRAB_SUCCESS)
587 	break;
588 
589       usleep(GRAB_WAIT * 1000);
590 
591       if (++grab_tries > GRAB_TRIES)
592 	{
593 	  gtk_widget_hide (dialog);
594 	  g_get_current_time (&fade_data->start_time);
595 	  while (fadein_callback (fade_data) != FALSE);
596 	  report_failed_grab (FAILED_GRAB_KEYBOARD);
597 	  exit (1);
598 	  break;
599 	}
600     }
601 
602   /* we "raise" the window because there is a race here for
603    * focus-follow-mouse and auto-raise WMs that may put the window
604    * in the background and confuse users
605    */
606   gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE);
607 
608   while (gtk_events_pending ())
609     gtk_main_iteration ();
610 
611   return lock;
612 }
613 
614 void
ungrab_keyboard_and_mouse(int lock)615 ungrab_keyboard_and_mouse (int lock)
616 {
617   /* Ungrab */
618   gdk_pointer_ungrab(GDK_CURRENT_TIME);
619   gdk_keyboard_ungrab(GDK_CURRENT_TIME);
620   gdk_flush();
621 
622   g_get_current_time (&fade_data->start_time);
623   while (fadein_callback (fade_data) != FALSE);
624   gdk_threads_leave();
625 
626   close(lock);
627 }
628 
629 static gchar*
get_gnome_keyring_password(GksuContext * context)630 get_gnome_keyring_password (GksuContext *context)
631 {
632   GnomeKeyringAttributeList *attributes;
633   GnomeKeyringAttribute attribute;
634   GnomeKeyringResult result;
635   GList *list;
636 
637   attributes = gnome_keyring_attribute_list_new ();
638 
639   attribute.name = g_strdup ("user");
640   attribute.type = GNOME_KEYRING_ATTRIBUTE_TYPE_STRING;
641   attribute.value.string = g_strdup (gksu_context_get_user (context));
642   g_array_append_val (attributes, attribute);
643 
644   attribute.name = g_strdup ("type");
645   attribute.type = GNOME_KEYRING_ATTRIBUTE_TYPE_STRING;
646   attribute.value.string = g_strdup ("local");
647   g_array_append_val (attributes, attribute);
648 
649   attribute.name = g_strdup ("creator");
650   attribute.type = GNOME_KEYRING_ATTRIBUTE_TYPE_STRING;
651   attribute.value.string = g_strdup ("gksu");
652   g_array_append_val (attributes, attribute);
653 
654   list = g_list_alloc();
655 
656   result = gnome_keyring_find_items_sync (GNOME_KEYRING_ITEM_GENERIC_SECRET,
657 					  attributes,
658 					  &list);
659   gnome_keyring_attribute_list_free (attributes);
660   if (
661       (result == GNOME_KEYRING_RESULT_OK) &&
662       (g_list_length(list) >= 1)
663       )
664     {
665       GnomeKeyringFound *found = list->data;
666       gint password_length = strlen (found->secret);
667       gchar *password;
668 
669       password = g_locale_from_utf8 (found->secret,
670 				     password_length,
671 				     NULL, NULL, NULL);
672       password_length = strlen (password);
673 
674       if (password[password_length-1] == '\n')
675 	password[password_length-1] = '\0';
676       return password;
677     }
678 
679   return NULL;
680 }
681 
682 static void
keyring_create_item_cb(GnomeKeyringResult result,guint32 id,gpointer keyring_loop)683 keyring_create_item_cb (GnomeKeyringResult result,
684                         guint32 id, gpointer keyring_loop)
685 {
686   g_main_loop_quit (keyring_loop);
687 }
688 
689 static void
set_gnome_keyring_password(GksuContext * context,gchar * password)690 set_gnome_keyring_password (GksuContext *context, gchar *password)
691 {
692   GConfClient *gconf_client;
693   gboolean save_to_keyring;
694 
695   gconf_client = context->gconf_client;
696   save_to_keyring = gconf_client_get_bool (gconf_client, BASE_PATH"save-to-keyring", NULL);
697 
698   if (password && save_to_keyring)
699     {
700       static GMainLoop *keyring_loop = NULL;
701       GnomeKeyringAttributeList *attributes;
702       GnomeKeyringAttribute attribute;
703       GnomeKeyringResult result;
704 
705       gchar *keyring_name;
706       gchar *key_name;
707 
708       attributes = gnome_keyring_attribute_list_new ();
709 
710       attribute.name = g_strdup ("user");
711       attribute.type = GNOME_KEYRING_ATTRIBUTE_TYPE_STRING;
712       attribute.value.string = g_strdup (gksu_context_get_user (context));
713       g_array_append_val (attributes, attribute);
714 
715       attribute.name = g_strdup ("type");
716       attribute.type = GNOME_KEYRING_ATTRIBUTE_TYPE_STRING;
717       attribute.value.string = g_strdup ("local");
718       g_array_append_val (attributes, attribute);
719 
720       attribute.name = g_strdup ("creator");
721       attribute.type = GNOME_KEYRING_ATTRIBUTE_TYPE_STRING;
722       attribute.value.string = g_strdup ("gksu");
723       g_array_append_val (attributes, attribute);
724 
725       key_name = g_strdup_printf ("Local password for user %s",
726 				  gksu_context_get_user (context));
727 
728       keyring_loop = g_main_loop_new (NULL, FALSE);
729 
730       keyring_name = gconf_client_get_string (gconf_client, BASE_PATH"save-keyring", NULL);
731       if (keyring_name == NULL)
732 	keyring_name = g_strdup ("session");
733 
734       /* make sure the keyring exists; if an error occurs, use
735          the session keyring */
736       result = gnome_keyring_create_sync(keyring_name, NULL);
737       if ((result != GNOME_KEYRING_RESULT_OK) &&
738 	  (result != GNOME_KEYRING_RESULT_ALREADY_EXISTS))
739 	keyring_name = g_strdup ("session");
740 
741       gnome_keyring_item_create (keyring_name,
742 				 GNOME_KEYRING_ITEM_GENERIC_SECRET,
743 				 key_name,
744 				 attributes,
745 				 password,
746 				 TRUE,
747 				 keyring_create_item_cb,
748 				 keyring_loop, NULL);
749       gnome_keyring_attribute_list_free (attributes);
750       g_free (keyring_name);
751       g_main_loop_run (keyring_loop);
752     }
753 }
754 
755 static void
unset_gnome_keyring_password(GksuContext * context)756 unset_gnome_keyring_password (GksuContext *context)
757 {
758   GConfClient *gconf_client;
759   gboolean save_to_keyring;
760 
761   GnomeKeyringAttributeList *attributes;
762   GnomeKeyringAttribute attribute;
763   GnomeKeyringResult result;
764   GList *list;
765 
766   gconf_client = context->gconf_client;
767   save_to_keyring = gconf_client_get_bool (gconf_client, BASE_PATH"save-to-keyring", NULL);
768 
769   if (save_to_keyring)
770     {
771       attributes = gnome_keyring_attribute_list_new ();
772 
773       attribute.name = g_strdup ("user");
774       attribute.type = GNOME_KEYRING_ATTRIBUTE_TYPE_STRING;
775       attribute.value.string = g_strdup (gksu_context_get_user (context));
776       g_array_append_val (attributes, attribute);
777 
778       attribute.name = g_strdup ("type");
779       attribute.type = GNOME_KEYRING_ATTRIBUTE_TYPE_STRING;
780       attribute.value.string = g_strdup ("local");
781       g_array_append_val (attributes, attribute);
782 
783       attribute.name = g_strdup ("creator");
784       attribute.type = GNOME_KEYRING_ATTRIBUTE_TYPE_STRING;
785       attribute.value.string = g_strdup ("gksu");
786       g_array_append_val (attributes, attribute);
787 
788       list = g_list_alloc();
789 
790       result = gnome_keyring_find_items_sync (GNOME_KEYRING_ITEM_GENERIC_SECRET,
791 					      attributes,
792 					      &list);
793       gnome_keyring_attribute_list_free (attributes);
794       if (
795 	  (result == GNOME_KEYRING_RESULT_OK) &&
796 	  (g_list_length(list) == 1)
797 	  )
798 	{
799 	  GnomeKeyringFound *found = list->data;
800 
801 	  gnome_keyring_item_delete_sync (found->keyring,
802 					  found->item_id);
803 	}
804     }
805 }
806 
807 void
get_configuration_options(GksuContext * context)808 get_configuration_options (GksuContext *context)
809 {
810   GConfClient *gconf_client = context->gconf_client;
811   gboolean force_grab;
812 
813   context->grab = !gconf_client_get_bool (gconf_client, BASE_PATH "disable-grab",
814 					  NULL);
815   force_grab = gconf_client_get_bool (gconf_client, BASE_PATH "force-grab",
816 				      NULL);
817   if (force_grab)
818     context->grab = TRUE;
819 
820   context->sudo_mode = gconf_client_get_bool (gconf_client, BASE_PATH "sudo-mode",
821 					      NULL);
822 }
823 
824 /**
825  * su_ask_password:
826  * @context: a #GksuContext
827  * @prompt: the prompt that should be used instead of "Password: "
828  * @data: data that is passed by gksu_*_full
829  * @error: a pointer to pointer #GError that will be filled with
830  * data if an error happens.
831  *
832  * This is a convenience function to create a #GksuuiDialog and
833  * request the password.
834  *
835  * Returns: a newly allocated gchar containing the password
836  * or NULL if an error happens or the user cancels the action
837  */
838 static gchar*
su_ask_password(GksuContext * context,gchar * prompt,gpointer data,GError ** error)839 su_ask_password (GksuContext *context, gchar *prompt,
840 		 gpointer data, GError **error)
841 {
842   GtkWidget *dialog = NULL;
843   gchar *msg;
844   gchar *password = NULL, *tmp = NULL;
845   int retvalue = 0;
846   int lock = 0;
847   GQuark gksu_quark;
848 
849   gksu_quark = g_quark_from_string (PACKAGE);
850 
851   if (context->grab)
852     dialog = g_object_new (GKSUUI_TYPE_DIALOG,
853 			   "type", GTK_WINDOW_POPUP,
854 			   "sudo-mode", context->sudo_mode,
855 			   NULL);
856   else
857     dialog = gksuui_dialog_new (context->sudo_mode);
858 
859   if (prompt)
860     gksuui_dialog_set_prompt (GKSUUI_DIALOG(dialog), _(prompt));
861 
862   if (context->message)
863     gksuui_dialog_set_message (GKSUUI_DIALOG(dialog), context->message);
864   else
865     {
866       gchar *command = NULL;
867       if (context->description)
868 	command = context->description;
869       else
870 	command = context->command;
871 
872       if (context->sudo_mode)
873 	{
874 	  if (!strcmp(context->user, "root"))
875 	    msg = g_strdup_printf (_("<b><big>Enter your password to perform"
876 				     " administrative tasks</big></b>\n\n"
877 				     "The application '%s' lets you "
878 				     "modify essential parts of your "
879 				     "system."),
880 				   command);
881 	  else
882 	    msg = g_strdup_printf (_("<b><big>Enter your password to run "
883 				     "the application '%s' as user %s"
884 				     "</big></b>"),
885 				   command, context->user);
886 	}
887       else
888 	{
889         if (strcmp(gksu_context_get_user (context), "root") == 0)
890           msg = g_strdup_printf (_("<b><big>Enter the administrative password"
891                                    "</big></b>\n\n"
892                                    "The application '%s' lets you "
893                                    "modify essential parts of your "
894                                    "system."),
895 				   command);
896         else
897           msg = g_strdup_printf (_("<b><big>Enter the password of %s to run "
898                                    "the application '%s'"
899                                    "</big></b>"),
900 				   context->user, command);
901       }
902 
903       gksuui_dialog_set_message (GKSUUI_DIALOG(dialog), msg);
904       g_free (msg);
905     }
906 
907   if (context->alert)
908     gksuui_dialog_set_alert (GKSUUI_DIALOG(dialog), context->alert);
909 
910   if (context->grab)
911     lock = grab_keyboard_and_mouse (dialog);
912   retvalue = gtk_dialog_run (GTK_DIALOG(dialog));
913   gtk_widget_hide (dialog);
914   if (context->grab)
915     ungrab_keyboard_and_mouse (lock);
916 
917   while (gtk_events_pending ())
918     gtk_main_iteration ();
919 
920   if (retvalue != GTK_RESPONSE_OK)
921     {
922       switch (retvalue)
923 	{
924 	case GTK_RESPONSE_CANCEL:
925 	case GTK_RESPONSE_DELETE_EVENT:
926 	  g_set_error (error, gksu_quark,
927 		       GKSU_ERROR_CANCELED,
928 		       _("Password prompt canceled."));
929 	  if (context->sn_context)
930 	    gksu_context_launch_complete (context);
931 	}
932 
933       gtk_widget_destroy (dialog);
934       while (gtk_events_pending ())
935 	gtk_main_iteration ();
936 
937       return NULL;
938     }
939 
940   tmp = gksuui_dialog_get_password (GKSUUI_DIALOG(dialog));
941   password = g_locale_from_utf8 (tmp, strlen (tmp), NULL, NULL, NULL);
942   g_free (tmp);
943 
944   gtk_widget_destroy (dialog);
945   while (gtk_events_pending ())
946     gtk_main_iteration ();
947 
948   return password;
949 }
950 
951 static void
cb_toggled_cb(GtkWidget * button,gpointer data)952 cb_toggled_cb (GtkWidget *button, gpointer data)
953 {
954   GConfClient *gconf_client;
955   gchar *key;
956   gboolean toggled;
957   gchar *key_name;
958 
959   g_return_if_fail (data != NULL);
960 
961   key_name = (gchar*)data;
962 
963   gconf_client = gconf_client_get_default ();
964   toggled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(button));
965 
966   key = g_strdup_printf (BASE_PATH "%s", key_name);
967 
968   if (!strcmp (key_name, "display-no-pass-info"))
969     {
970       /* the meaning of the key is the exact opposite of the meaning
971 	 of the answer - when the check button is checked the key must
972 	 be off
973       */
974       gconf_client_set_bool (gconf_client, key, !toggled, NULL);
975     }
976   else
977     gconf_client_set_bool (gconf_client, key, toggled, NULL);
978 
979   g_object_unref (gconf_client);
980 
981   g_free (key);
982 }
983 
984 void
no_pass(GksuContext * context,gpointer data)985 no_pass (GksuContext *context, gpointer data)
986 {
987   GtkWidget *dialog;
988   GtkWidget *alignment;
989   GtkWidget *check_button;
990 
991   gchar *command = NULL;
992 
993   if (context->description)
994     command = context->description;
995   else
996     command = context->command;
997 
998   dialog = gtk_message_dialog_new_with_markup (NULL, 0,
999 					       GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
1000 					       _("<b><big>Granted permissions without asking "
1001 						 "for password</big></b>"
1002 						 "\n\n"
1003 						 "The '%s' program was started with "
1004 						 "the privileges of the %s user without "
1005 						 "the need to ask for a password, due to "
1006 						 "your system's authentication mechanism "
1007 						 "setup."
1008 						 "\n\n"
1009 						 "It is possible that you are being allowed "
1010 						 "to run specific programs as user %s "
1011 						 "without the need for a password, or that "
1012 						 "the password is cached."
1013 						 "\n\n"
1014 						 "This is not a problem report; it's "
1015 						 "simply a notification to make sure "
1016 						 "you are aware of this."),
1017 					       command,
1018 					       context->user,
1019 					       context->user);
1020 
1021   alignment = gtk_alignment_new (0.5, 0.5, 0.6, 1);
1022   gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), alignment, TRUE, TRUE, 2);
1023 
1024   check_button = gtk_check_button_new_with_mnemonic (_("Do _not display this message again"));
1025   g_signal_connect (G_OBJECT(check_button), "toggled",
1026 		    G_CALLBACK(cb_toggled_cb), "display-no-pass-info");
1027   gtk_container_add (GTK_CONTAINER(alignment), check_button);
1028 
1029   gtk_widget_show_all (dialog);
1030   gtk_dialog_run (GTK_DIALOG(dialog));
1031   gtk_widget_destroy (GTK_WIDGET(dialog));
1032 
1033   while (gtk_events_pending ())
1034     gtk_main_iteration ();
1035 }
1036 
1037 static void
gksu_prompt_grab(GksuContext * context)1038 gksu_prompt_grab (GksuContext *context)
1039 {
1040   GtkWidget *d;
1041 
1042   d = gtk_message_dialog_new_with_markup (NULL, 0, GTK_MESSAGE_QUESTION,
1043 					  GTK_BUTTONS_YES_NO,
1044 					  _("<b>Would you like your screen to be \"grabbed\"\n"
1045 					    "while you enter the password?</b>"
1046 					    "\n\n"
1047 					    "This means all applications will be paused to avoid\n"
1048 					    "the eavesdropping of your password by a a malicious\n"
1049 					    "application while you type it."));
1050 
1051   if (gtk_dialog_run (GTK_DIALOG(d)) == GTK_RESPONSE_NO)
1052     context->grab = FALSE;
1053   else
1054     context->grab = TRUE;
1055 
1056   gtk_widget_destroy (d);
1057 }
1058 
1059 static void
nullify_password(gchar * pass)1060 nullify_password (gchar *pass)
1061 {
1062   if (pass)
1063     {
1064       memset(pass, 0, strlen(pass));
1065       g_free (pass);
1066     }
1067   pass = NULL;
1068 }
1069 
1070 static gchar *
get_process_name(pid_t pid)1071 get_process_name (pid_t pid)
1072 {
1073   static gboolean init;
1074   glibtop_proc_state buf;
1075 
1076   if (!init) {
1077     glibtop_init();
1078     init = TRUE;
1079   }
1080 
1081   glibtop_get_proc_state (&buf, pid);
1082   return strdup(buf.cmd);
1083 }
1084 
1085 static gchar *
get_xauth_token(GksuContext * context,gchar * display)1086 get_xauth_token (GksuContext *context, gchar *display)
1087 {
1088   gchar *xauth_bin = NULL;
1089   FILE *xauth_output;
1090   gchar *tmp = NULL;
1091   gchar *xauth = g_new0 (gchar, 256);
1092 
1093   /* find out where the xauth binary is located */
1094   if (g_file_test ("/usr/local/bin/xauth", G_FILE_TEST_IS_EXECUTABLE))
1095     xauth_bin = "/usr/local/bin/xauth";
1096   else if (g_file_test ("/usr/X11R6/bin/xauth", G_FILE_TEST_IS_EXECUTABLE))
1097     xauth_bin = "/usr/X11R6/bin/xauth";
1098   else
1099     {
1100       fprintf (stderr,
1101 	       "Failed to obtain xauth key: xauth binary not found "
1102 	       "at usual locations");
1103 
1104       return NULL;
1105     }
1106 
1107   /* get the authorization token */
1108   tmp = g_strdup_printf ("%s list %s | "
1109 			 "head -1 | awk '{ print $3 }'",
1110 			 xauth_bin,
1111 			 display);
1112   if ((xauth_output = popen (tmp, "r")) == NULL)
1113     {
1114       fprintf (stderr,
1115 	       "Failed to obtain xauth key: %s",
1116 	       strerror(errno));
1117       return NULL;
1118     }
1119   fread (xauth, sizeof(char), 255, xauth_output);
1120   pclose (xauth_output);
1121   g_free (tmp);
1122 
1123   if (context->debug)
1124     {
1125       fprintf(stderr,
1126 	      "xauth: -%s-\n"
1127 	      "display: -%s-\n",
1128 	      xauth, display);
1129     }
1130 
1131   return xauth;
1132 }
1133 
1134 /**
1135  * prepare_xauth:
1136  *
1137  * Sets up the variables with values for the $DISPLAY
1138  * environment variable and xauth-related stuff. Also
1139  * creates a temporary directory to hold a .Xauthority
1140  *
1141  * Returns: TRUE if it suceeds, FALSE if it fails.
1142  */
1143 static int
prepare_xauth(GksuContext * context)1144 prepare_xauth (GksuContext *context)
1145 {
1146   gchar *display = NULL;
1147   gchar *xauth = NULL;
1148 
1149   display = g_strdup (getenv ("DISPLAY"));
1150   xauth = get_xauth_token (context, display);
1151   if (xauth == NULL)
1152     {
1153       g_free (display);
1154       return FALSE;
1155     }
1156 
1157   /* If xauth is the empty string, then try striping the
1158    * hostname part of the DISPLAY string for getting the
1159    * auth token; this is needed for ssh-forwarded usage
1160    */
1161   if (!strcmp ("", xauth))
1162     {
1163       gchar *cut_display = NULL;
1164 
1165       g_free (xauth);
1166       cut_display = g_strdup (g_strrstr (display, ":"));
1167       xauth = get_xauth_token (context, cut_display);
1168 
1169       g_free (display);
1170       display = cut_display;
1171     }
1172 
1173   context->xauth = xauth;
1174   context->display = display;
1175 
1176   if (context->debug)
1177     {
1178       fprintf(stderr,
1179 	      "final xauth: -%s-\n"
1180 	      "final display: -%s-\n",
1181 	      context->xauth, context->display);
1182     }
1183 
1184   return TRUE;
1185 }
1186 
1187 /* Write all of buf, even if write(2) is interrupted. */
1188 static ssize_t
full_write(int d,const char * buf,size_t nbytes)1189 full_write (int d, const char *buf, size_t nbytes)
1190 {
1191   ssize_t r, w = 0;
1192 
1193   /* Loop until nbytes of buf have been written. */
1194   while (w < nbytes) {
1195     /* Keep trying until write succeeds without interruption. */
1196     do {
1197       r = write(d, buf + w, nbytes - w);
1198     } while (r < 0 && errno == EINTR);
1199 
1200     if (r < 0) {
1201       return -1;
1202     }
1203 
1204     w += r;
1205   }
1206 
1207   return w;
1208 }
1209 
1210 static gboolean
copy(const char * fn,const char * dir)1211 copy (const char *fn, const char *dir)
1212 {
1213   int in, out;
1214   int r;
1215   char *newfn;
1216   char buf[BUFSIZ] = "";
1217 
1218   newfn = g_strdup_printf("%s/.Xauthority", dir);
1219 
1220   out = open(newfn, O_WRONLY | O_CREAT | O_EXCL, 0600);
1221   if (out == -1)
1222     {
1223       if (errno == EEXIST)
1224 	fprintf (stderr,
1225 		 "Impossible to create the .Xauthority file: a file "
1226 		 "already exists. This might be a security issue; "
1227 		 "please investigate.");
1228       else
1229 	fprintf (stderr,
1230 		 "Error copying '%s' to '%s': %s",
1231 		 fn, dir, strerror(errno));
1232 
1233       return FALSE;
1234     }
1235 
1236   in = open(fn, O_RDONLY);
1237   if (in == -1)
1238     {
1239       fprintf (stderr,
1240 	       "Error copying '%s' to '%s': %s",
1241 	       fn, dir, strerror(errno));
1242       return FALSE;
1243     }
1244 
1245   while ((r = read(in, buf, BUFSIZ)) > 0)
1246     {
1247       if (full_write(out, buf, r) == -1)
1248 	{
1249 	  fprintf (stderr,
1250 		   "Error copying '%s' to '%s': %s",
1251 		   fn, dir, strerror(errno));
1252 	  return FALSE;
1253 	}
1254     }
1255 
1256   if (r == -1)
1257     {
1258       fprintf (stderr,
1259 	       "Error copying '%s' to '%s': %s",
1260 	       fn, dir, strerror(errno));
1261       return FALSE;
1262     }
1263 
1264   return TRUE;
1265 }
1266 
1267 static gboolean
sudo_prepare_xauth(GksuContext * context)1268 sudo_prepare_xauth (GksuContext *context)
1269 {
1270   gchar template[] = "/tmp/" PACKAGE "-XXXXXX";
1271   gboolean error_copying = FALSE;
1272   gchar *xauth = NULL;
1273 
1274   context->dir = g_strdup (mkdtemp(template));
1275   if (!context->dir)
1276     {
1277       fprintf (stderr, strerror(errno));
1278       return FALSE;
1279     }
1280 
1281   xauth = g_strdup(g_getenv ("XAUTHORITY"));
1282   if (xauth == NULL)
1283     xauth = g_strdup_printf ("%s/.Xauthority", g_get_home_dir());
1284 
1285   error_copying = !copy (xauth, context->dir);
1286   g_free (xauth);
1287 
1288   if (error_copying)
1289     return FALSE;
1290 
1291   return TRUE;
1292 }
1293 
1294 static void
sudo_reset_xauth(GksuContext * context,gchar * xauth,gchar * xauth_env)1295 sudo_reset_xauth (GksuContext *context, gchar *xauth,
1296 		  gchar *xauth_env)
1297 {
1298   /* reset the env var as it was before or clean it  */
1299   if (xauth_env)
1300     setenv ("XAUTHORITY", xauth_env, TRUE);
1301   else
1302     unsetenv ("XAUTHORITY");
1303 
1304   if (context->debug)
1305     fprintf (stderr, "xauth: %s\nxauth_env: %s\ndir: %s\n",
1306 	     xauth, xauth_env, context->dir);
1307 
1308   unlink (xauth);
1309   rmdir (context->dir);
1310 
1311   g_free (xauth);
1312 }
1313 
1314 static void
startup_notification_initialize(GksuContext * context)1315 startup_notification_initialize (GksuContext *context)
1316 {
1317   SnDisplay *sn_display;
1318   sn_display = sn_display_new (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()),
1319 			       NULL, NULL);
1320   context->sn_context = sn_launcher_context_new (sn_display, gdk_screen_get_number (gdk_display_get_default_screen (gdk_display_get_default ())));
1321   sn_launcher_context_set_description (context->sn_context, _("Granting Rights"));
1322   sn_launcher_context_set_name (context->sn_context, g_get_prgname ());
1323 }
1324 
1325 /**
1326  * gksu_context_new
1327  *
1328  * This function should be used when creating a new #GksuContext to
1329  * pass to gksu_su_full or gksu_sudo_full. The #GksuContext must be
1330  * freed with gksu_context_free.
1331  *
1332  * Returns: a newly allocated #GksuContext
1333  */
1334 GksuContext*
gksu_context_new()1335 gksu_context_new ()
1336 {
1337   GksuContext *context;
1338 
1339   context = g_new (GksuContext, 1);
1340 
1341   context->xauth = NULL;
1342   context->dir = NULL;
1343   context->display = NULL;
1344 
1345   context->gconf_client = gconf_client_get_default ();
1346 
1347   context->sudo_mode = FALSE;
1348 
1349   context->user = g_strdup ("root");
1350   context->command = NULL;
1351 
1352   context->login_shell = FALSE;
1353   context->keep_env = FALSE;
1354 
1355   context->description = NULL;
1356   context->message = NULL;
1357   context->alert = NULL;
1358   context->grab = TRUE;
1359   context->always_ask_password = FALSE;
1360 
1361   context->debug = FALSE;
1362 
1363   context->sn_context = NULL;
1364   context->sn_id = NULL;
1365 
1366   context->ref_count = 1;
1367 
1368   get_configuration_options (context);
1369   startup_notification_initialize (context);
1370 
1371   return context;
1372 }
1373 
1374 /**
1375  * gksu_context_set_user:
1376  * @context: the #GksuContext you want to modify
1377  * @username: the target username
1378  *
1379  * Sets up what user the command will be run as. The default
1380  * is root, but you can run the command as any user.
1381  *
1382  */
1383 void
gksu_context_set_user(GksuContext * context,gchar * username)1384 gksu_context_set_user (GksuContext *context, gchar *username)
1385 {
1386   g_assert (username != NULL);
1387 
1388   if (context->user)
1389     g_free (context->user);
1390   context->user = g_strdup (username);
1391 }
1392 
1393 /**
1394  * gksu_context_get_user:
1395  * @context: the #GksuContext from which to grab the information
1396  *
1397  * Gets the user the command will be run as, as set
1398  * by gksu_context_set_user.
1399  *
1400  * Returns: a string with the user or NULL if not set.
1401  */
1402 const gchar*
gksu_context_get_user(GksuContext * context)1403 gksu_context_get_user (GksuContext *context)
1404 {
1405   return context->user;
1406 }
1407 
1408 /**
1409  * gksu_context_set_command:
1410  * @context: the #GksuContext you want to modify
1411  * @command: the command that shall be ran
1412  *
1413  * Sets up what command will run with the target user.
1414  *
1415  */
1416 void
gksu_context_set_command(GksuContext * context,gchar * command)1417 gksu_context_set_command (GksuContext *context, gchar *command)
1418 {
1419   g_assert (command != NULL);
1420 
1421   if (context->command)
1422     g_free (context->command);
1423   context->command = g_strdup (command);
1424 
1425   /* startup notification */
1426   sn_launcher_context_set_binary_name (context->sn_context,
1427 				       command);
1428 }
1429 
1430 /**
1431  * gksu_context_get_command:
1432  * @context: the #GksuContext from which to grab the information
1433  *
1434  * Gets the command that will be run, as set by
1435  * gksu_context_set_command.
1436  *
1437  * Returns: a string with the command or NULL if not set.
1438  */
1439 const gchar*
gksu_context_get_command(GksuContext * context)1440 gksu_context_get_command (GksuContext *context)
1441 {
1442   return context->command;
1443 }
1444 
1445 /**
1446  * gksu_context_set_login_shell:
1447  * @context: the #GksuContext you want to modify
1448  * @value: TRUE or FALSE
1449  *
1450  * Should the shell in which the command will be run be
1451  * a login shell?
1452  */
1453 void
gksu_context_set_login_shell(GksuContext * context,gboolean value)1454 gksu_context_set_login_shell (GksuContext *context, gboolean value)
1455 {
1456   context->login_shell = value;
1457 }
1458 
1459 /**
1460  * gksu_context_get_login_shell:
1461  * @context: the #GksuContext from which to grab the information
1462  *
1463  * Finds out if the shell created by the underlying su process
1464  * will be a login shell.
1465  *
1466  * Returns: TRUE if the shell will be a login shell, FALSE otherwise.
1467  */
1468 gboolean
gksu_context_get_login_shell(GksuContext * context)1469 gksu_context_get_login_shell (GksuContext *context)
1470 {
1471   return context->login_shell;
1472 }
1473 
1474 /**
1475  * gksu_context_set_keep_env:
1476  * @context: the #GksuContext you want to modify
1477  * @value: TRUE or FALSE
1478  *
1479  * Should the environment be kept as it is? Defaults to
1480  * TRUE. Notice that setting this to FALSE may cause the
1481  * X authorization stuff to fail.
1482  */
1483 void
gksu_context_set_keep_env(GksuContext * context,gboolean value)1484 gksu_context_set_keep_env (GksuContext *context, gboolean value)
1485 {
1486   context->keep_env = value;
1487 }
1488 
1489 /**
1490  * gksu_context_get_keep_env:
1491  * @context: the #GksuContext from which to grab the information
1492  *
1493  * Finds out if the environment in which the program will be
1494  * run will be reset.
1495  *
1496  * Returns: TRUE if the environment is going to be kept,
1497  * FALSE otherwise.
1498  */
1499 gboolean
gksu_context_get_keep_env(GksuContext * context)1500 gksu_context_get_keep_env (GksuContext *context)
1501 {
1502   return context->keep_env;
1503 }
1504 
1505 /**
1506  * gksu_context_set_description:
1507  * @context: the #GksuContext you want to modify
1508  * @description: a string to set the description for
1509  *
1510  * Set the nice name for the action that is being run that the window
1511  * that asks for the password will have.  This is only meant to be
1512  * used if the default window is used, of course.
1513  */
1514 void
gksu_context_set_description(GksuContext * context,gchar * description)1515 gksu_context_set_description (GksuContext *context, gchar *description)
1516 {
1517   if (context->description)
1518     g_free (context->description);
1519   context->description = g_strdup (description);
1520 }
1521 
1522 /**
1523  * gksu_context_get_description:
1524  * @context: the #GksuContext you want to get the description from.
1525  *
1526  * Get the description that the window will have when the
1527  * default function for requesting the password is
1528  * called.
1529  *
1530  * Returns: a string with the description or NULL if not set.
1531  */
1532 gchar*
gksu_context_get_description(GksuContext * context)1533 gksu_context_get_description (GksuContext *context)
1534 {
1535   return context->description;
1536 }
1537 
1538 /**
1539  * gksu_context_set_message:
1540  * @context: the #GksuContext you want to modify
1541  * @message: a string to set the message for
1542  *
1543  * Set the message that the window that asks for the password will have.
1544  * This is only meant to be used if the default window is used, of course.
1545  */
1546 void
gksu_context_set_message(GksuContext * context,gchar * message)1547 gksu_context_set_message (GksuContext *context, gchar *message)
1548 {
1549   if (context->message)
1550     g_free (context->message);
1551   context->message = g_strdup (message);
1552 }
1553 
1554 /**
1555  * gksu_context_get_message:
1556  * @context: the #GksuContext you want to get the message from.
1557  *
1558  * Get the message that the window will have when the
1559  * default function for requesting the password is
1560  * called.
1561  *
1562  * Returns: a string with the message or NULL if not set.
1563  */
1564 gchar*
gksu_context_get_message(GksuContext * context)1565 gksu_context_get_message (GksuContext *context)
1566 {
1567   return context->message;
1568 }
1569 
1570 /**
1571  * gksu_context_set_alert:
1572  * @context: the #GksuContext you want to modify
1573  * @alert: a string to set the alert for
1574  *
1575  * Set the alert that the window that asks for the password will have.
1576  * This is only meant to be used if the default window is used, of course.
1577  * This alert should be used to display messages such as 'incorrect password',
1578  * for instance.
1579  */
1580 void
gksu_context_set_alert(GksuContext * context,gchar * alert)1581 gksu_context_set_alert (GksuContext *context, gchar *alert)
1582 {
1583   if (context->alert)
1584     g_free (context->alert);
1585   context->alert = g_strdup (alert);
1586 }
1587 
1588 /**
1589  * gksu_context_get_alert:
1590  * @context: the #GksuContext you want to get the alert from.
1591  *
1592  * Get the alert that the window will have when the
1593  * default function for requesting the password is
1594  * called.
1595  *
1596  * Returns: a string with the alert or NULL if not set.
1597  */
1598 gchar*
gksu_context_get_alert(GksuContext * context)1599 gksu_context_get_alert (GksuContext *context)
1600 {
1601   return context->alert;
1602 }
1603 
1604 /**
1605  * gksu_context_set_debug:
1606  * @context: the #GksuContext you want to modify
1607  * @value: TRUE or FALSE
1608  *
1609  * Set up if debuging information should be printed.
1610  */
1611 void
gksu_context_set_grab(GksuContext * context,gboolean value)1612 gksu_context_set_grab (GksuContext *context, gboolean value)
1613 {
1614   context->grab = value;
1615 }
1616 
1617 /**
1618  * gksu_context_get_grab:
1619  * @context: the #GksuContext you want to ask whether a grab will be done.
1620  *
1621  * Returns TRUE if gksu has been asked to do a grab on keyboard and mouse
1622  * when asking for the password.
1623  *
1624  * Returns: TRUE if yes, FALSE otherwise.
1625  */
1626 gboolean
gksu_context_get_grab(GksuContext * context)1627 gksu_context_get_grab (GksuContext *context)
1628 {
1629   return context->grab;
1630 }
1631 
1632 /**
1633  * gksu_context_set_always_ask_password:
1634  * @context: the #GksuContext you want to modify
1635  * @value: TRUE or FALSE
1636  *
1637  * Set up if gksu should always ask for a password. Notice that this
1638  * will only work when passwords are cached, as done by gnome-keyring
1639  * for gksu's su mode and by sudo for gksu's sudo mode, but will have no
1640  * effect if su or sudo are set up to not require the password at all.
1641  */
1642 void
gksu_context_set_always_ask_password(GksuContext * context,gboolean value)1643 gksu_context_set_always_ask_password (GksuContext *context, gboolean value)
1644 {
1645   context->always_ask_password = value;
1646 }
1647 
1648 /**
1649  * gksu_context_get_always_ask_password:
1650  * @context: the #GksuContext you want to ask whether a grab will be done.
1651  *
1652  * Returns TRUE if gksu has been asked to always ask for a password
1653  * (even if sudo or gnome-keyring have cached it)
1654  *
1655  * Returns: TRUE if yes, FALSE otherwise.
1656  */
1657 gboolean
gksu_context_get_always_ask_password(GksuContext * context)1658 gksu_context_get_always_ask_password (GksuContext *context)
1659 {
1660    return context->always_ask_password;
1661 }
1662 
1663 
1664 /**
1665  * gksu_context_set_launcher_context:
1666  * @context: the #GksuContext you want to set the sn context in
1667  * @sn_context: the #SnLauncherContext you want to set
1668  *
1669  * Tell libgksu to use the given #SnLauncherContext for startup notification.
1670  * Currently the library will use this to set DESKTOP_STARTUP_ID in the
1671  * environment of the child and to issue initiate and complete events.
1672  * Notice that you don't need to use this function unless you want to
1673  * override gksu's default behavior on startup notification, since the
1674  * library will create its own context.
1675  *
1676  * Returns: the #SnLauncherContext which is set, or NULL if none was set
1677  */
1678 void
gksu_context_set_launcher_context(GksuContext * context,SnLauncherContext * sn_context)1679 gksu_context_set_launcher_context (GksuContext *context,
1680 				   SnLauncherContext *sn_context)
1681 {
1682   if (context->sn_context)
1683     sn_launcher_context_unref (context->sn_context);
1684   context->sn_context = sn_context;
1685 }
1686 
1687 /**
1688  * gksu_context_get_launcher_context:
1689  * @context: the #GksuContext you want to get the sn context from
1690  *
1691  * Gets the current startup notification launcher context
1692  *
1693  * Returns: the #SnLauncherContext which is set, or NULL if none was set
1694  */
1695 SnLauncherContext*
gksu_context_get_launcher_context(GksuContext * context)1696 gksu_context_get_launcher_context (GksuContext *context)
1697 {
1698   return context->sn_context;
1699 }
1700 
1701 /**
1702  * gksu_context_set_launcher_id:
1703  * @context: the #GksuContext you want to set the sn id in
1704  * @sn_context: the sn_id you want to set, as a #gchar
1705  */
1706 void
gksu_context_set_launcher_id(GksuContext * context,gchar * sn_id)1707 gksu_context_set_launcher_id (GksuContext *context,
1708 			      gchar *sn_id)
1709 {
1710   if (context->sn_id)
1711     g_free (context->sn_id);
1712   context->sn_id = g_strdup(sn_id);
1713 }
1714 
1715 /**
1716  * gksu_context_launch_initiate:
1717  * @context: the #GksuContext you want to initiate the launch for
1718  *
1719  * Initiates the launch, as far as Startup Notification is concerned;
1720  * This will only be used internally, usually.
1721  */
1722 static void
gksu_context_launch_initiate(GksuContext * context)1723 gksu_context_launch_initiate (GksuContext *context)
1724 {
1725   gchar *sid = NULL;
1726   guint32 launch_time = gdk_x11_display_get_user_time (gdk_display_get_default ());
1727   static gboolean initiated = FALSE;
1728 
1729   if (!initiated)
1730     initiated = TRUE;
1731   else
1732     return;
1733 
1734   sn_launcher_context_initiate (context->sn_context,
1735 				g_get_prgname (),
1736 				gksu_context_get_command (context),
1737 				launch_time);
1738 
1739   sid = g_strdup_printf ("%s", sn_launcher_context_get_startup_id (context->sn_context));
1740   gksu_context_set_launcher_id (context, sid);
1741 
1742   if (context->debug)
1743     fprintf (stderr, "STARTUP_ID: %s\n", sid);
1744   setenv ("DESKTOP_STARTUP_ID", sid, TRUE);
1745   g_free(sid);
1746 }
1747 
1748 /**
1749  * gksu_context_launch_complete:
1750  * @context: the #GksuContext you want to complete the launch for
1751  *
1752  * Completes the launch, as far as Startup Notification is concerned;
1753  * This will only be used internally, usually.
1754  */
1755 static void
gksu_context_launch_complete(GksuContext * context)1756 gksu_context_launch_complete (GksuContext *context)
1757 {
1758   sn_launcher_context_complete(context->sn_context);
1759 }
1760 
1761 /**
1762  * gksu_context_set_debug:
1763  * @context: the #GksuContext you want to modify
1764  * @value: TRUE or FALSE
1765  *
1766  * Set up if debuging information should be printed.
1767  */
1768 void
gksu_context_set_debug(GksuContext * context,gboolean value)1769 gksu_context_set_debug (GksuContext *context, gboolean value)
1770 {
1771   context->debug = value;
1772 }
1773 
1774 /**
1775  * gksu_context_get_debug:
1776  * @context: the #GksuContext from which to grab the information
1777  *
1778  * Finds out if the library is configured to print debuging
1779  * information.
1780  *
1781  * Returns: TRUE if it is, FALSE otherwise.
1782  */
1783 gboolean
gksu_context_get_debug(GksuContext * context)1784 gksu_context_get_debug (GksuContext *context)
1785 {
1786   return context->debug;
1787 }
1788 
1789 /**
1790  * gksu_context_free
1791  * @context: the #GksuContext to be freed.
1792  *
1793  * Frees the given #GksuContext.
1794  */
1795 void
gksu_context_free(GksuContext * context)1796 gksu_context_free (GksuContext *context)
1797 {
1798   g_free (context->xauth);
1799   g_free (context->dir);
1800   g_free (context->display);
1801 
1802   g_object_unref (context->gconf_client);
1803 
1804   g_free (context->description);
1805   g_free (context->message);
1806 
1807   g_free (context->user);
1808   g_free (context->command);
1809 
1810   g_free (context);
1811 }
1812 
1813 /**
1814  * gksu_context_ref
1815  * @context: A #GksuContext struct.
1816  *
1817  * Increments the reference count of the given #GksuContext.
1818  */
1819 GksuContext*
gksu_context_ref(GksuContext * context)1820 gksu_context_ref (GksuContext *context)
1821 {
1822   context->ref_count++;
1823   return context;
1824 }
1825 
1826 /**
1827  * gksu_context_unref
1828  * @context: A #GksuContext struct.
1829  *
1830  * Decrements the reference count of the given #GksuContext struct,
1831  * freeing it if the reference count falls to zero.
1832  */
1833 void
gksu_context_unref(GksuContext * context)1834 gksu_context_unref (GksuContext *context)
1835 {
1836   if (--context->ref_count == 0)
1837     {
1838         gksu_context_free (context);
1839     }
1840 }
1841 
1842 GType
gksu_context_get_type(void)1843 gksu_context_get_type (void)
1844 {
1845   static GType type_gksu_context = 0;
1846 
1847   if (!type_gksu_context)
1848     type_gksu_context = g_boxed_type_register_static
1849       ("GksuContext",
1850        (GBoxedCopyFunc) gksu_context_ref,
1851        (GBoxedFreeFunc) gksu_context_unref);
1852 
1853   return type_gksu_context;
1854 }
1855 
1856 
1857 /**
1858  * gksu_su_full:
1859  * @context: a #GksuContext
1860  * @ask_pass: a #GksuAskPassFunc to be called when the lib determines
1861  * requesting a password is necessary; it may be NULL, in which case
1862  * the standard password request dialog will be used
1863  * @ask_pass_data: a #gpointer with user data to be passed to the
1864  * #GksuAskPasswordFunc
1865  * @pass_not_needed: a #GksuPassNotNeededFunc that will be called
1866  * when the command is being run without the need for requesting
1867  * a password; it will only be called if the display-no-pass-info
1868  * gconf key is enabled; NULL will have the standard dialog be shown
1869  * @pass_not_needed_data: a #gpointer with the user data to be passed to the
1870  * #GksuPasswordNotNeededFunc
1871  * @error: a #GError object to be filled with the error code or NULL
1872  *
1873  * This is a compatibility shim over gksu_su_fuller, which, for
1874  * compatibility reasons, lacks the 'exit_status' argument. You should
1875  * check the documentation for gksu_su_fuller for information about
1876  * the arguments.
1877  *
1878  * Returns: TRUE if all went fine, FALSE if failed
1879  */
1880 
1881 gboolean
gksu_su_full(GksuContext * context,GksuAskPassFunc ask_pass,gpointer ask_pass_data,GksuPassNotNeededFunc pass_not_needed,gpointer pass_not_needed_data,GError ** error)1882 gksu_su_full (GksuContext *context,
1883 	      GksuAskPassFunc ask_pass,
1884 	      gpointer ask_pass_data,
1885 	      GksuPassNotNeededFunc pass_not_needed,
1886 	      gpointer pass_not_needed_data,
1887 	      GError **error)
1888 {
1889   return gksu_su_fuller(context,
1890   			ask_pass, ask_pass_data,
1891 			pass_not_needed, pass_not_needed_data,
1892 			NULL, error);
1893 }
1894 
1895 
1896 /**
1897  * gksu_su_fuller:
1898  * @context: a #GksuContext
1899  * @ask_pass: a #GksuAskPassFunc to be called when the lib determines
1900  * requesting a password is necessary; it may be NULL, in which case
1901  * the standard password request dialog will be used
1902  * @ask_pass_data: a #gpointer with user data to be passed to the
1903  * #GksuAskPasswordFunc
1904  * @pass_not_needed: a #GksuPassNotNeededFunc that will be called
1905  * when the command is being run without the need for requesting
1906  * a password; it will only be called if the display-no-pass-info
1907  * gconf key is enabled; NULL will have the standard dialog be shown
1908  * @pass_not_needed_data: a #gpointer with the user data to be passed to the
1909  * #GksuPasswordNotNeededFunc
1910  * @exit_status: an optional pointer to a #gint8 which will be filled with
1911  * the exit status of the child process
1912  * @error: a #GError object to be filled with the error code or NULL
1913  *
1914  * This could be considered one of the main functions in GKSu.
1915  * it is responsible for doing the 'user changing' magic calling
1916  * the #GksuAskPassFunc function to request a password if needed.
1917  * and the #GksuPassNotNeededFunc function if a password won't be
1918  * needed, so the application has the oportunity of warning the user
1919  * what it's doing.
1920  *
1921  * This function uses su as backend.
1922  *
1923  * Returns: TRUE if all went fine, FALSE if failed
1924  */
1925 gboolean
gksu_su_fuller(GksuContext * context,GksuAskPassFunc ask_pass,gpointer ask_pass_data,GksuPassNotNeededFunc pass_not_needed,gpointer pass_not_needed_data,gint8 * exit_status,GError ** error)1926 gksu_su_fuller (GksuContext *context,
1927 	        GksuAskPassFunc ask_pass,
1928 	        gpointer ask_pass_data,
1929 	        GksuPassNotNeededFunc pass_not_needed,
1930 	        gpointer pass_not_needed_data,
1931 	        gint8 *exit_status,
1932 	        GError **error)
1933 {
1934   GQuark gksu_quark;
1935   int i = 0;
1936 
1937   gchar auxcommand[] = PREFIX "/lib/" PACKAGE "/gksu-run-helper";
1938 
1939   int fdpty;
1940   pid_t pid;
1941 
1942   context->sudo_mode = FALSE;
1943 
1944   gksu_quark = g_quark_from_string (PACKAGE);
1945 
1946   if (!context->command)
1947     {
1948       g_set_error (error, gksu_quark, GKSU_ERROR_NOCOMMAND,
1949 		   _("gksu_run needs a command to be run, "
1950 		     "none was provided."));
1951       return FALSE;
1952     }
1953 
1954   if (!context->user)
1955     context->user = g_strdup ("root");
1956 
1957   if (!g_file_test (auxcommand, G_FILE_TEST_IS_EXECUTABLE))
1958     {
1959       g_set_error (error, gksu_quark, GKSU_ERROR_HELPER,
1960 		   _("The gksu-run-helper command was not found or "
1961 		     "is not executable."));
1962       return FALSE;
1963     }
1964 
1965   if (!prepare_xauth (context))
1966     {
1967       g_set_error (error, gksu_quark, GKSU_ERROR_XAUTH,
1968 		   _("Unable to copy the user's Xauthorization file."));
1969       return FALSE;
1970     }
1971 
1972   if (context->sn_context)
1973     gksu_context_launch_initiate (context);
1974 
1975   pid = forkpty(&fdpty, NULL, NULL, NULL);
1976   if (pid == 0)
1977     {
1978       gchar **cmd = g_malloc (sizeof(gchar*)*7);
1979 
1980       setsid();   // make us session leader
1981       cmd[i] = g_strdup ("/usr/bin/su"); i++;
1982       if (context->login_shell)
1983 	{
1984 	  cmd[i] = g_strdup ("-"); i++;
1985 	}
1986       cmd[i] = g_strdup (context->user); i++;
1987       if (context->keep_env)
1988 	{
1989 	  cmd[i] = g_strdup ("-p"); i++;
1990 	}
1991       cmd[i] = g_strdup ("-c"); i++;
1992 
1993       /* needs to get X authorization prior to running the program */
1994       cmd[i] = g_strdup_printf ("%s \"%s\"", auxcommand,
1995 				context->command); i++;
1996 
1997       cmd[i] = NULL;
1998 
1999       /* executes the command */
2000       if (execv (cmd[0], cmd) == -1)
2001 	{
2002 	  fprintf (stderr,
2003 		   "Unable to run /usr/bin/su: %s",
2004 		   strerror(errno));
2005 	}
2006 
2007       for (i = 0 ; cmd[i] != NULL ; i++)
2008 	g_free (cmd[i]);
2009       g_free(cmd);
2010     }
2011   else if (pid == -1)
2012     {
2013       g_set_error (error, gksu_quark, GKSU_ERROR_FORK,
2014 		   _("Failed to fork new process: %s"),
2015 		   strerror(errno));
2016       return FALSE;
2017     }
2018   else
2019     {
2020       fd_set rfds;
2021 
2022       struct timeval tv;
2023 
2024       struct passwd *pwd = NULL;
2025       gint target_uid = -1;
2026       gint my_uid = 0;
2027 
2028       gchar buf[256] = {0};
2029       gint status;
2030 
2031       gchar *password = NULL;
2032       gchar *cmdline = NULL;
2033       gboolean password_needed = FALSE;
2034       gboolean used_gnome_keyring = FALSE;
2035 
2036       my_uid = getuid();
2037       pwd = getpwnam (context->user);
2038       if (pwd)
2039 	target_uid = pwd->pw_uid;
2040 
2041       if (ask_pass == NULL)
2042 	{
2043 	  ask_pass = su_ask_password;
2044 	}
2045 
2046       if (pass_not_needed == NULL)
2047 	{
2048 	  pass_not_needed = no_pass;
2049 	}
2050 
2051       /* no need to ask for password if we're already root */
2052       if (my_uid != target_uid && my_uid)
2053 	{
2054 	  gint count;
2055 	  struct termios tio;
2056 
2057 	  read (fdpty, buf, 255);
2058 	  if (context->debug)
2059 	    fprintf (stderr, "gksu_context_run: buf: -%s-\n", buf);
2060 
2061 	  /* make sure we notice that ECHO is turned off, if it gets
2062 	     turned off */
2063 	  tcgetattr (fdpty, &tio);
2064 	  for (count = 0; (tio.c_lflag & ECHO) && count < 15; count++)
2065 	    {
2066 	      usleep (1000);
2067 	      tcgetattr (fdpty, &tio);
2068 	    }
2069 
2070 	  if (!(tio.c_lflag & ECHO))
2071 	    {
2072 	      gboolean prompt_grab;
2073 	      prompt_grab = gconf_client_get_bool (context->gconf_client, BASE_PATH "prompt",
2074 						   NULL);
2075 
2076 	      if (prompt_grab)
2077 		gksu_prompt_grab (context);
2078 
2079               /* try to get the password from the GNOME Keyring first, but
2080 	       * only if we have not been requested to always ask for the
2081 	       * password
2082 	       */
2083 	      if (!context->always_ask_password)
2084 	        password = get_gnome_keyring_password (context);
2085 	      if (password == NULL)
2086 		{
2087 		  password = ask_pass (context, buf, ask_pass_data, error);
2088 		  if (context->debug)
2089 		    {
2090 		      fprintf (stderr, "no password on keyring\n");
2091 		      if (password == NULL)
2092 			fprintf (stderr, "no password from ask_pass!\n");
2093 		    }
2094 		}
2095 	      else
2096 		{
2097 		  if (context->debug)
2098 		    fprintf (stderr, "password from keyring found\n");
2099 		  used_gnome_keyring = TRUE;
2100 		}
2101 	      if (password == NULL || (error && (*error)))
2102 		{
2103 		  if (context->debug)
2104 		    fprintf (stderr, "gksu_su_full: problem getting password - getting out\n");
2105 		  if (context->debug && error)
2106 		    fprintf (stderr, "error: %s\n", (*error)->message);
2107 		  nullify_password (password);
2108 		  return TRUE;
2109 		}
2110 
2111 	      write (fdpty, password, strlen(password) + 1);
2112 	      write (fdpty, "\n", 1);
2113 	      password_needed = TRUE;
2114 	    }
2115 	}
2116 
2117       if (context->debug)
2118 	fprintf (stderr, "DEBUG (run:after-pass) buf: -%s-\n", buf);
2119       if (strncmp (buf, "gksu", 4) && strncmp (buf, "su", 2))
2120 	{
2121 	  /* drop the \n echoed on password entry if su did request
2122 	     a password */
2123 	  if (password_needed)
2124 	    read (fdpty, buf, 255);
2125 	  if (context->debug)
2126 	    fprintf (stderr, "DEBUG (run:post-after-pass) buf: -%s-\n", buf);
2127 	  read (fdpty, buf, 255);
2128 	  if (context->debug)
2129 	    fprintf (stderr, "DEBUG (run:post-after-pass) buf: -%s-\n", buf);
2130 	}
2131 
2132       FD_ZERO (&rfds);
2133       FD_SET (fdpty, &rfds);
2134       tv.tv_sec = 1;
2135       tv.tv_usec = 0;
2136       int loop_count = 0;
2137       while (TRUE)
2138 	{
2139 	  int retval = 0;
2140 
2141 	  if (!strncmp (buf, "su", 2))
2142 	    {
2143 	      gchar **strings;
2144 
2145 	      if (password)
2146 		{
2147 		  nullify_password (password);
2148 		  unset_gnome_keyring_password (context);
2149 		}
2150 
2151 	      strings = g_strsplit (buf, ":", 2);
2152 	      if (strings[1] && !strncmp (strings[1], " Authentication failure", 23))
2153 		{
2154 		  if (used_gnome_keyring)
2155 		    g_set_error (error, gksu_quark,
2156 				 GKSU_ERROR_WRONGAUTOPASS,
2157 				 _("Wrong password got from keyring."));
2158 		  else
2159 		    g_set_error (error, gksu_quark,
2160 				 GKSU_ERROR_WRONGPASS,
2161 				 _("Wrong password."));
2162 		}
2163 	      g_strfreev (strings);
2164 
2165 	      if (context->debug)
2166 		fprintf (stderr, "DEBUG (auth_failed) buf: -%s-\n", buf);
2167 
2168 	      break;
2169 	    }
2170 	  else if (!strncmp (buf, "gksu: waiting", 13))
2171 	    {
2172 	      gchar *line;
2173 
2174 	      if (password)
2175 		{
2176 		  set_gnome_keyring_password (context, password);
2177 		  nullify_password (password);
2178 		}
2179 
2180 	      if (context->debug)
2181 		fprintf (stderr, "DEBUG (gksu: waiting) buf: -%s-\n", buf);
2182 
2183 	      line = g_strdup_printf ("gksu-run: %s\n", context->display);
2184 	      write (fdpty, line, strlen(line));
2185 	      g_free (line);
2186 
2187 	      line = g_strdup_printf ("gksu-run: %s\n", context->sn_id);
2188 	      write (fdpty, line, strlen(line));
2189 	      g_free (line);
2190 
2191 	      line = g_strdup_printf ("gksu-run: %s\n", context->xauth);
2192 	      write (fdpty, line, strlen(line));
2193 	      g_free (line);
2194 
2195 	      bzero (buf, 256);
2196 	      read (fdpty, buf, 255);
2197 
2198 	      break;
2199 	    }
2200 
2201 	  retval = select (fdpty + 1, &rfds, NULL, NULL, &tv);
2202 	  if ((loop_count > 50) || (!retval))
2203 	    {
2204 	      gchar *emsg = NULL;
2205 	      gchar *converted_str = NULL;
2206 	      GError *converr = NULL;
2207 
2208 	      if (password)
2209 		nullify_password (password);
2210 
2211 	      converted_str = g_locale_to_utf8 (buf, -1, NULL, NULL, &converr);
2212 	      if (converr)
2213 		{
2214 		  g_warning (_("Failed to communicate with "
2215 			       "gksu-run-helper.\n\n"
2216 			       "Received:\n"
2217 			       " %s\n"
2218 			       "While expecting:\n"
2219 			       " %s"), buf, "gksu: waiting");
2220 		  emsg = g_strdup_printf (_("Failed to communicate with "
2221 					    "gksu-run-helper.\n\n"
2222 					    "Received bad string "
2223 					    "while expecting:\n"
2224 					    " %s"), "gksu: waiting");
2225 		  g_error_free (converr);
2226 		}
2227 	      else
2228 		emsg = g_strdup_printf (_("Failed to communicate with "
2229 					  "gksu-run-helper.\n\n"
2230 					  "Received:\n"
2231 					  " %s\n"
2232 					  "While expecting:\n"
2233 					  " %s"), converted_str, "gksu: waiting");
2234 	      g_free (converted_str);
2235 
2236 	      g_set_error (error, gksu_quark, GKSU_ERROR_HELPER, emsg);
2237 	      g_free (emsg);
2238 
2239 	      if (context->debug)
2240 		fprintf (stderr, "DEBUG (failed!) buf: -%s-\n", buf);
2241 
2242 	      return FALSE;
2243 	    }
2244 	  else if (retval == -1)
2245 	    {
2246 	      if (context->debug)
2247 		fprintf (stderr, "DEBUG (select failed!) buf: %s\n", buf);
2248 	      return FALSE;
2249 	    }
2250 
2251 	  read (fdpty, buf, 255);
2252 	  if (context->debug)
2253 	    fprintf (stderr, "DEBUG (run:after-pass) buf: -%s-\n", buf);
2254 	  loop_count++;
2255 	}
2256 
2257       if (!password_needed || used_gnome_keyring)
2258 	{
2259 	  gboolean should_display;
2260 
2261 	  should_display = gconf_client_get_bool (context->gconf_client,
2262 						  BASE_PATH "display-no-pass-info", NULL);
2263 
2264 	  /* configuration tells us to show this message */
2265 	  if (should_display)
2266 	    {
2267 	      if (context->debug)
2268 		fprintf (stderr, "Calling pass_not_needed window...\n");
2269 	      pass_not_needed (context, pass_not_needed_data);
2270 	      /* make sure it is displayed */
2271 	      while (gtk_events_pending ())
2272 		gtk_main_iteration ();
2273 	    }
2274 	}
2275 
2276       cmdline = g_strdup("bin/su");
2277       /* wait for the child process to end or become something other
2278 	 than su */
2279       pid_t pid_exited;
2280       while ((!(pid_exited = waitpid (pid, &status, WNOHANG))) &&
2281 	     (g_str_has_suffix(cmdline, "bin/su")))
2282 	{
2283 	  if (cmdline)
2284 	    g_free (cmdline);
2285 	  cmdline = get_process_name (pid);
2286 	  usleep(100000);
2287 	}
2288 
2289       if (context->sn_context)
2290 	gksu_context_launch_complete (context);
2291 
2292       bzero(buf, 256);
2293       while (read (fdpty, buf, 255) > 0)
2294 	{
2295 	  fprintf (stderr, "%s", buf);
2296 	  bzero(buf, 256);
2297 	}
2298 
2299       if (pid_exited != pid)
2300 	waitpid(pid, &status, 0);
2301 
2302       if (exit_status)
2303       {
2304       	if (WIFEXITED(status)) {
2305       	  *exit_status = WEXITSTATUS(status);
2306 	} else if (WIFSIGNALED(status)) {
2307 	  *exit_status = -1;
2308 	}
2309       }
2310 
2311       if (WEXITSTATUS(status))
2312 	{
2313 	  if(cmdline)
2314 	    {
2315 	      /* su already exec()ed something else, don't report
2316 	       * exit status errors in that case
2317 	       */
2318 	      if (!g_str_has_suffix (cmdline, "su"))
2319 		{
2320 		  g_free (cmdline);
2321 		  return FALSE;
2322 		}
2323 	      g_free (cmdline);
2324 	    }
2325 
2326 	  if (error == NULL)
2327 	    g_set_error (error, gksu_quark,
2328 			 GKSU_ERROR_CHILDFAILED,
2329 			 _("su terminated with %d status"),
2330 			 WEXITSTATUS(status));
2331 	}
2332     }
2333 
2334   if (error)
2335     return FALSE;
2336 
2337   return TRUE;
2338 }
2339 
2340 /**
2341  * gksu_su
2342  * @command_line: the command line that will be executed as other user
2343  * @error: a #GError to be set with the error condition, if an error
2344  * happens
2345  *
2346  * This function is a wrapper for gksu_su_run_full. It will call it
2347  * without giving the callback functions, which leads to the standard
2348  * ones being called. A simple #GksuContext is created to hold the
2349  * user name and the command.
2350  *
2351  * Returns: TRUE if all went well, FALSE if an error happend.
2352  */
2353 gboolean
gksu_su(gchar * command_line,GError ** error)2354 gksu_su (gchar *command_line, GError **error)
2355 {
2356   GksuContext *context = gksu_context_new ();
2357   gboolean retval;
2358 
2359   context->command = g_strdup (command_line);
2360   context->user = g_strdup ("root");
2361   retval = gksu_su_full (context,
2362 			 NULL, NULL,
2363 			 NULL, NULL,
2364 			 error);
2365   gksu_context_free (context);
2366   return retval;
2367 }
2368 
2369 static void
read_line(int fd,gchar * buffer,int n)2370 read_line (int fd, gchar *buffer, int n)
2371 {
2372   gint counter = 0;
2373   gchar tmp[2] = {0};
2374 
2375   for (; counter < (n - 1); counter++)
2376     {
2377       tmp[0] = '\0';
2378       read (fd, tmp, 1);
2379       if (tmp[0] == '\n')
2380 	break;
2381       buffer[counter] = tmp[0];
2382     }
2383   buffer[counter] = '\0';
2384 }
2385 
2386 /**
2387  * gksu_sudo_full:
2388  * @context: a #GksuContext
2389  * @ask_pass: a #GksuAskPassFunc to be called when the lib determines
2390  * requesting a password is necessary; it may be NULL, in which case
2391  * the standard password request dialog will be used
2392  * @ask_pass_data: a #gpointer with user data to be passed to the
2393  * #GksuAskPasswordFunc
2394  * @pass_not_needed: a #GksuPassNotNeededFunc that will be called
2395  * when the command is being run without the need for requesting
2396  * a password; it will only be called if the display-no-pass-info
2397  * gconf key is enabled; NULL will have the standard dialog be shown
2398  * @pass_not_needed_data: a #gpointer with the user data to be passed to the
2399  * #GksuPasswordNotNeededFunc
2400  * @error: a #GError object to be filled with the error code or NULL
2401  *
2402  * This is a compatibility shim over gksu_sudo_fuller, which, for
2403  * compatibility reasons, lacks the 'exit_status' argument. You should
2404  * check the documentation for gksu_sudo_fuller for information about
2405  * the arguments.
2406  *
2407  * Returns: TRUE if all went fine, FALSE if failed
2408  */
2409 
2410 gboolean
gksu_sudo_full(GksuContext * context,GksuAskPassFunc ask_pass,gpointer ask_pass_data,GksuPassNotNeededFunc pass_not_needed,gpointer pass_not_needed_data,GError ** error)2411 gksu_sudo_full (GksuContext *context,
2412 		GksuAskPassFunc ask_pass,
2413 		gpointer ask_pass_data,
2414 		GksuPassNotNeededFunc pass_not_needed,
2415 		gpointer pass_not_needed_data,
2416 		GError **error)
2417 {
2418   return gksu_sudo_fuller(context,
2419   			  ask_pass, ask_pass_data,
2420 			  pass_not_needed, pass_not_needed_data,
2421 			  NULL, error);
2422 }
2423 
2424 /**
2425  * gksu_sudo_fuller:
2426  * @context: a #GksuContext
2427  * @ask_pass: a #GksuAskPassFunc to be called when the lib determines
2428  * requesting a password is necessary; it may be NULL, in which case
2429  * the standard password request dialog will be used
2430  * @ask_pass_data: a #gpointer with user data to be passed to the
2431  * #GksuAskPasswordFunc
2432  * @pass_not_needed: a #GksuPassNotNeededFunc that will be called
2433  * when the command is being run without the need for requesting
2434  * a password; it will only be called if the display-no-pass-info
2435  * gconf key is enabled; NULL will have the standard dialog be shown
2436  * @pass_not_needed_data: a #gpointer with the user data to be passed to the
2437  * #GksuPasswordNotNeededFunc
2438  * @error: a #GError object to be filled with the error code or NULL
2439  * @exit_status: an optional pointer to a #gint8 which will be filled with
2440  * the exit status of the child process
2441  *
2442  * This could be considered one of the main functions in GKSu.
2443  * it is responsible for doing the 'user changing' magic calling
2444  * the #GksuAskPassFunc function to request a password if needed.
2445  * and the #GksuPassNotNeededFunc function if a password won't be
2446  * needed, so the application has the oportunity of warning the user
2447  * what it's doing.
2448  *
2449  * This function uses the sudo backend.
2450  *
2451  * Returns: TRUE if all went fine, FALSE if failed
2452  */
2453 gboolean
gksu_sudo_fuller(GksuContext * context,GksuAskPassFunc ask_pass,gpointer ask_pass_data,GksuPassNotNeededFunc pass_not_needed,gpointer pass_not_needed_data,gint8 * exit_status,GError ** error)2454 gksu_sudo_fuller (GksuContext *context,
2455 		  GksuAskPassFunc ask_pass,
2456 		  gpointer ask_pass_data,
2457 		  GksuPassNotNeededFunc pass_not_needed,
2458 		  gpointer pass_not_needed_data,
2459 		  gint8 *exit_status,
2460 		  GError **error)
2461 {
2462   char **cmd;
2463   char buffer[256] = {0};
2464   int argcount = 8;
2465   int i, j;
2466 
2467   GQuark gksu_quark;
2468 
2469   gchar *xauth = NULL,
2470     *xauth_env = NULL;
2471 
2472   pid_t pid;
2473   int status;
2474   FILE *infile, *outfile;
2475   int parent_pipe[2];	/* For talking to the parent */
2476   int child_pipe[2];	/* For talking to the child */
2477 
2478   context->sudo_mode = TRUE;
2479 
2480   gksu_quark = g_quark_from_string (PACKAGE);
2481 
2482   if (!context->command)
2483     {
2484       g_set_error (error, gksu_quark, GKSU_ERROR_NOCOMMAND,
2485 		   _("gksu_sudo_run needs a command to be run, "
2486 		     "none was provided."));
2487       return FALSE;
2488     }
2489 
2490   if (!context->user)
2491     context->user = g_strdup ("root");
2492 
2493   if (ask_pass == NULL)
2494     {
2495       if (context->debug)
2496 	fprintf (stderr, "No ask_pass set, using default!\n");
2497       ask_pass = su_ask_password;
2498     }
2499   if (pass_not_needed == NULL)
2500     {
2501       pass_not_needed = no_pass;
2502     }
2503 
2504   if (context->always_ask_password)
2505     {
2506        gint exit_status;
2507        g_spawn_command_line_sync("/usr/local/bin/sudo -K", NULL, NULL, &exit_status, NULL);
2508     }
2509 
2510 
2511   /*
2512      FIXME: need to set GError in a more detailed way
2513   */
2514   if (!sudo_prepare_xauth (context))
2515     {
2516       g_set_error (error, gksu_quark, GKSU_ERROR_XAUTH,
2517 		   _("Unable to copy the user's Xauthorization file."));
2518       return FALSE;
2519     }
2520 
2521   /* sets XAUTHORITY */
2522   xauth = g_strdup_printf ("%s/.Xauthority", context->dir);
2523   xauth_env = getenv ("XAUTHORITY");
2524   setenv ("XAUTHORITY", xauth, TRUE);
2525   if (context->debug)
2526     fprintf (stderr, "xauth: %s\n", xauth);
2527 
2528   /* set startup id */
2529   if (context->sn_context)
2530     gksu_context_launch_initiate (context);
2531 
2532   cmd = g_new (gchar *, argcount + 1);
2533 
2534   argcount = 0;
2535 
2536   /* sudo binary */
2537   cmd[argcount] = g_strdup("/usr/local/bin/sudo");
2538   argcount++;
2539 
2540   if (!context->keep_env)
2541     {
2542       /* Make sudo set $HOME */
2543       cmd[argcount] = g_strdup("-H");
2544       argcount++;
2545     }
2546 
2547   /* Make sudo read from stdin */
2548   cmd[argcount] = g_strdup("-S");
2549   argcount++;
2550 
2551   /* Make sudo use next arg as prompt */
2552   cmd[argcount] = g_strdup("-p");
2553   argcount++;
2554 
2555   /* prompt */
2556   cmd[argcount] = g_strdup("GNOME_SUDO_PASS");
2557   argcount++;
2558 
2559   /* Make sudo use the selected user */
2560   cmd[argcount] = g_strdup("-u");
2561   argcount++;
2562 
2563   /* user */
2564   cmd[argcount] = g_strdup(context->user);
2565   argcount++;
2566 
2567   /* sudo does not understand this if we do not use -H
2568      weird.
2569   */
2570   if (!context->keep_env)
2571     {
2572       /* Make sudo stop processing options */
2573       cmd[argcount] = g_strdup("--");
2574       argcount++;
2575     }
2576 
2577   {
2578     gchar *tmp_arg = g_malloc (sizeof(gchar)*1);
2579     gboolean inside_quotes = FALSE;
2580 
2581     tmp_arg[0] = '\0';
2582 
2583     for (i = j = 0; ; i++)
2584       {
2585 	if ((context->command[i] == '\'') && (context->command[i-1] != '\\'))
2586 	  {
2587 	    i = i + 1;
2588 	    inside_quotes = !inside_quotes;
2589 	  }
2590 
2591 	if ((context->command[i] == ' ' && inside_quotes == FALSE)
2592 	    || context->command[i] == '\0')
2593 	  {
2594 	    tmp_arg = g_realloc (tmp_arg, sizeof(gchar)*(j+1));
2595 	    tmp_arg[j] = '\0';
2596 	    cmd = g_realloc (cmd, sizeof(gchar*) * (argcount + 1));
2597 	    cmd[argcount] = g_strdup (tmp_arg);
2598 
2599 	    g_free (tmp_arg);
2600 
2601 	    argcount = argcount + 1;
2602 	    j = 0;
2603 
2604 	    if (context->command[i] == '\0')
2605 	      break;
2606 
2607 	    tmp_arg = g_malloc (sizeof(gchar)*1);
2608 	    tmp_arg[0] = '\0';
2609 	  }
2610 	else
2611 	  {
2612 	    if (context->command[i] == '\\' && context->command[i+1] != '\\')
2613 	      i = i + 1;
2614 	    tmp_arg = g_realloc (tmp_arg, sizeof(gchar)*(j+1));
2615 	    tmp_arg[j] = context->command[i];
2616 	    j = j + 1;
2617 	  }
2618       }
2619   }
2620   cmd = g_realloc (cmd, sizeof(gchar*) * (argcount + 1));
2621   cmd[argcount] = NULL;
2622 
2623   if (context->debug)
2624     {
2625       for (i = 0; cmd[i] != NULL; i++)
2626 	fprintf (stderr, "cmd[%d]: %s\n", i, cmd[i]);
2627     }
2628 
2629   if ((pipe(parent_pipe)) == -1)
2630     {
2631       g_set_error (error, gksu_quark, GKSU_ERROR_PIPE,
2632 		   _("Error creating pipe: %s"),
2633 		   strerror(errno));
2634       sudo_reset_xauth (context, xauth, xauth_env);
2635       return FALSE;
2636     }
2637 
2638   if ((pipe(child_pipe)) == -1)
2639     {
2640       g_set_error (error, gksu_quark, GKSU_ERROR_PIPE,
2641 		   _("Error creating pipe: %s"),
2642 		   strerror(errno));
2643       sudo_reset_xauth (context, xauth, xauth_env);
2644       return FALSE;
2645     }
2646 
2647   pid = fork();
2648   if (pid == -1)
2649     {
2650       g_set_error (error, gksu_quark, GKSU_ERROR_FORK,
2651 		   _("Failed to fork new process: %s"),
2652 		   strerror(errno));
2653       sudo_reset_xauth (context, xauth, xauth_env);
2654       return FALSE;
2655     }
2656   else if (pid == 0)
2657     {
2658       // Child
2659       setsid();   // make us session leader
2660       close(child_pipe[1]);
2661       dup2(child_pipe[0], STDIN_FILENO);
2662       dup2(parent_pipe[1], STDERR_FILENO);
2663 
2664       execv(cmd[0], cmd);
2665 
2666       g_set_error (error, gksu_quark, GKSU_ERROR_EXEC,
2667 		   _("Failed to exec new process: %s"),
2668 		   strerror(errno));
2669       sudo_reset_xauth (context, xauth, xauth_env);
2670       return FALSE;
2671     }
2672   else
2673     {
2674       gint counter = 0;
2675       gchar *cmdline = NULL;
2676 
2677       // Parent
2678       close(parent_pipe[1]);
2679 
2680       infile = fdopen(parent_pipe[0], "r");
2681       if (!infile)
2682 	{
2683 	  g_set_error (error, gksu_quark, GKSU_ERROR_PIPE,
2684 		       _("Error opening pipe: %s"),
2685 		       strerror(errno));
2686 	  sudo_reset_xauth (context, xauth, xauth_env);
2687 	  return FALSE;
2688 	}
2689 
2690       outfile = fdopen(child_pipe[1], "w");
2691       if (!outfile)
2692 	{
2693 	  g_set_error (error, gksu_quark, GKSU_ERROR_PIPE,
2694 		       _("Error opening pipe: %s"),
2695 		       strerror(errno));
2696 	  sudo_reset_xauth (context, xauth, xauth_env);
2697 	  return FALSE;
2698 	}
2699 
2700       /*
2701 	we are expecting to receive a GNOME_SUDO_PASS
2702 	if we don't there are two possibilities: an error
2703 	or a password is not needed
2704       */
2705       fcntl (parent_pipe[0], F_SETFL, O_NONBLOCK);
2706 
2707       { /* no matter if we can read, since we're using
2708 	   O_NONBLOCK; this is just to avoid the prompt
2709 	   showing up after the read */
2710 	fd_set rfds;
2711 	struct timeval tv;
2712 
2713 	FD_ZERO(&rfds);
2714 	FD_SET(parent_pipe[0], &rfds);
2715 	tv.tv_sec = 1;
2716 	tv.tv_usec = 0;
2717 
2718 	select (parent_pipe[0] + 1, &rfds, NULL, NULL, &tv);
2719       }
2720 
2721       /* Try hard to find the prompt; it may happen that we're
2722        * seeing sudo's lecture, or that some pam module is spitting
2723        * debugging stuff at the screen
2724        */
2725       for (counter = 0; counter < 50; counter++)
2726 	{
2727 	  if (strncmp (buffer, "GNOME_SUDO_PASS", 15) == 0)
2728 	    break;
2729 
2730 	  read_line (parent_pipe[0], buffer, 256);
2731 
2732 	  if (context->debug)
2733 	    fprintf (stderr, "buffer: -%s-\n", buffer);
2734 
2735 	  usleep(1000);
2736 	}
2737 
2738       if (context->debug)
2739 	fprintf (stderr, "brute force GNOME_SUDO_PASS ended...\n");
2740 
2741       if (strncmp(buffer, "GNOME_SUDO_PASS", 15) == 0)
2742 	{
2743 	  gchar *password = NULL;
2744 	  gboolean prompt_grab;
2745 
2746 	  if (context->debug)
2747 	    fprintf (stderr, "Yeah, we're in...\n");
2748 
2749 	  prompt_grab = gconf_client_get_bool (context->gconf_client, BASE_PATH "prompt",
2750 						   NULL);
2751 	  if (prompt_grab)
2752 	    gksu_prompt_grab (context);
2753 
2754 	  password = ask_pass (context, _("Password: "),
2755 			       ask_pass_data, error);
2756 	  if (password == NULL || (*error))
2757 	    {
2758 	      nullify_password (password);
2759 	      return FALSE;
2760 	    }
2761 
2762 	  usleep (1000);
2763 
2764 	  fprintf (outfile, "%s\n", password);
2765 	  fclose (outfile);
2766 
2767 	  nullify_password (password);
2768 
2769 	  /* turn NONBLOCK off */
2770 	  fcntl(parent_pipe[0], F_SETFL, fcntl(parent_pipe[0], F_GETFL) & ~O_NONBLOCK);
2771 	  /* ignore the first newline that comes right after sudo receives
2772 	     the password */
2773 	  fgets (buffer, 255, infile);
2774 	  /* this is the status we are interessted in */
2775 	  fgets (buffer, 255, infile);
2776 	}
2777       else
2778 	{
2779 	  gboolean should_display;
2780 	  if (context->debug)
2781 	    fprintf (stderr, "No password prompt found; we'll assume we don't need a password.\n");
2782 
2783           /* turn NONBLOCK off, also if have no prompt */
2784           fcntl(parent_pipe[0], F_SETFL, fcntl(parent_pipe[0], F_GETFL) & ~O_NONBLOCK);
2785 
2786 	  should_display = gconf_client_get_bool (context->gconf_client,
2787 						  BASE_PATH "display-no-pass-info", NULL);
2788 
2789 	  /* configuration tells us to show this message */
2790 	  if (should_display)
2791 	    {
2792 	      if (context->debug)
2793 		fprintf (stderr, "Calling pass_not_needed window...\n");
2794 	      pass_not_needed (context, pass_not_needed_data);
2795 	      /* make sure it is displayed */
2796 	      while (gtk_events_pending ())
2797 		gtk_main_iteration ();
2798 	    }
2799 
2800 	  fprintf (stderr, "%s", buffer);
2801 	}
2802 
2803       if (!strcmp (buffer, "Sorry, try again.\n"))
2804 	g_set_error (error, gksu_quark, GKSU_ERROR_WRONGPASS,
2805 		     _("Wrong password."));
2806       else if (!strncmp (buffer, "Sorry, user ", 12))
2807 	g_set_error (error, gksu_quark, GKSU_ERROR_NOT_ALLOWED,
2808 		     _("The underlying authorization mechanism (sudo) "
2809 		       "does not allow you to run this program. Contact "
2810 		       "the system administrator."));
2811       else
2812 	{
2813 	  gchar *haystack = buffer;
2814 	  gchar *needle;
2815 
2816 	  needle = g_strstr_len (haystack, strlen (haystack), " ");
2817 	  if (needle && (needle + 1))
2818 	    {
2819 	      needle += 1;
2820 	      if (!strncmp (needle, "is not in", 9))
2821 		g_set_error (error, gksu_quark, GKSU_ERROR_NOT_ALLOWED,
2822 			     _("The underlying authorization mechanism (sudo) "
2823 			       "does not allow you to run this program. Contact "
2824 			       "the system administrator."));
2825 	    }
2826 	}
2827 
2828       cmdline = g_strdup("sudo");
2829       /* wait for the child process to end or become something other
2830 	 than sudo */
2831       pid_t pid_exited;
2832       while ((!(pid_exited = waitpid (pid, &status, WNOHANG))) &&
2833 	     (g_str_has_suffix(cmdline, "sudo")))
2834 	{
2835 	  if (cmdline)
2836 	    g_free (cmdline);
2837 	  cmdline = get_process_name (pid);
2838 	  usleep(100000);
2839 	}
2840 
2841       if (context->sn_context)
2842 	gksu_context_launch_complete (context);
2843 
2844       while (read (parent_pipe[0], buffer, 255) > 0)
2845 	{
2846 	  fprintf (stderr, "%s", buffer);
2847 	  bzero(buffer, 256);
2848 	}
2849 
2850       /* if the process is still active waitpid() on it */
2851       if (pid_exited != pid)
2852 	waitpid(pid, &status, 0);
2853       sudo_reset_xauth (context, xauth, xauth_env);
2854 
2855       if (exit_status)
2856       {
2857       	if (WIFEXITED(status)) {
2858       	  *exit_status = WEXITSTATUS(status);
2859 	} else if (WIFSIGNALED(status)) {
2860 	  *exit_status = -1;
2861 	}
2862       }
2863 
2864       if (WEXITSTATUS(status))
2865 	{
2866 	  if(cmdline)
2867 	    {
2868 	      /* sudo already exec()ed something else, don't report
2869 	       * exit status errors in that case
2870 	       */
2871 	      if (!g_str_has_suffix (cmdline, "sudo"))
2872 		{
2873 		  g_free (cmdline);
2874 		  return FALSE;
2875 		}
2876 	      g_free (cmdline);
2877 	    }
2878 	  if (error == NULL)
2879 	    g_set_error (error, gksu_quark,
2880 			 GKSU_ERROR_CHILDFAILED,
2881 			 _("sudo terminated with %d status"),
2882 			 WEXITSTATUS(status));
2883 	}
2884     }
2885 
2886   /* if error is set we have found an error condition */
2887   if (error)
2888     return FALSE;
2889 
2890   return TRUE;
2891 }
2892 
2893 /**
2894  * gksu_sudo
2895  * @command_line: the command line that will be executed as other user
2896  * @error: a #GError to be set with the error condition, if an error
2897  * happens
2898  *
2899  * This function is a wrapper for gksu_sudo_run_full. It will call it
2900  * without giving the callback functions, which leads to the standard
2901  * ones being called. A simple #GksuContext is created to hold the
2902  * user name and the command.
2903  *
2904  * Returns: TRUE if all went well, FALSE if an error happend.
2905  */
2906 gboolean
gksu_sudo(gchar * command_line,GError ** error)2907 gksu_sudo (gchar *command_line,
2908 	   GError **error)
2909 {
2910   GksuContext *context = gksu_context_new ();
2911   gboolean retval;
2912 
2913   context->command = g_strdup (command_line);
2914   context->user = g_strdup ("root");
2915   retval = gksu_sudo_full (context,
2916 			   NULL, NULL,
2917 			   NULL, NULL,
2918 			   error);
2919   gksu_context_free (context);
2920 
2921   return retval;
2922 }
2923 
2924 /**
2925  * gksu_run_full:
2926  * @context: a #GksuContext
2927  * @ask_pass: a #GksuAskPassFunc to be called when the lib determines
2928  * requesting a password is necessary; it may be NULL, in which case
2929  * the standard password request dialog will be used
2930  * @ask_pass_data: a #gpointer with user data to be passed to the
2931  * #GksuAskPasswordFunc
2932  * @pass_not_needed: a #GksuPassNotNeededFunc that will be called
2933  * when the command is being run without the need for requesting
2934  * a password; it will only be called if the display-no-pass-info
2935  * gconf key is enabled; NULL will have the standard dialog be shown
2936  * @pass_not_needed_data: a #gpointer with the user data to be passed to the
2937  * #GksuPasswordNotNeededFunc
2938  * @error: a #GError object to be filled with the error code or NULL
2939  *
2940  * This is a compatibility shim over gksu_run_fuller, which, for
2941  * compatibility reasons, lacks the 'exit_status' argument.
2942  *
2943  * Returns: TRUE if all went fine, FALSE if failed
2944  */
2945 
2946 gboolean
gksu_run_full(GksuContext * context,GksuAskPassFunc ask_pass,gpointer ask_pass_data,GksuPassNotNeededFunc pass_not_needed,gpointer pass_not_needed_data,GError ** error)2947 gksu_run_full (GksuContext *context,
2948 	       GksuAskPassFunc ask_pass,
2949 	       gpointer ask_pass_data,
2950 	       GksuPassNotNeededFunc pass_not_needed,
2951 	       gpointer pass_not_needed_data,
2952 	       GError **error)
2953 {
2954   return gksu_run_fuller(context,
2955   			 ask_pass, ask_pass_data,
2956 			 pass_not_needed, pass_not_needed_data,
2957 			 NULL, error);
2958 }
2959 
2960 /**
2961  * gksu_run_fuller:
2962  * @context: a #GksuContext
2963  * @ask_pass: a #GksuAskPassFunc to be called when the lib determines
2964  * requesting a password is necessary; it may be NULL, in which case
2965  * the standard password request dialog will be used
2966  * @ask_pass_data: a #gpointer with user data to be passed to the
2967  * #GksuAskPasswordFunc
2968  * @pass_not_needed: a #GksuPassNotNeededFunc that will be called
2969  * when the command is being run without the need for requesting
2970  * a password; it will only be called if the display-no-pass-info
2971  * gconf key is enabled; NULL will have the standard dialog be shown
2972  * @pass_not_needed_data: a #gpointer with the user data to be passed to the
2973  * #GksuPasswordNotNeededFunc
2974  * @exit_status: an optional pointer to a #gint8 which will be filled with
2975  * the exit status of the child process
2976  * @error: a #GError object to be filled with the error code or NULL
2977  *
2978  * This function is a wrapper for gksu_sudo_full/gksu_su_full. It will
2979  * call one of them, depending on the GConf key that defines whether
2980  * the default behavior for gksu is su or sudo mode. This is the
2981  * recommended way of using the library functionality.
2982  *
2983  * Returns: TRUE if all went fine, FALSE if failed
2984  */
2985 gboolean
gksu_run_fuller(GksuContext * context,GksuAskPassFunc ask_pass,gpointer ask_pass_data,GksuPassNotNeededFunc pass_not_needed,gpointer pass_not_needed_data,gint8 * exit_status,GError ** error)2986 gksu_run_fuller (GksuContext *context,
2987 	         GksuAskPassFunc ask_pass,
2988 	         gpointer ask_pass_data,
2989 	         GksuPassNotNeededFunc pass_not_needed,
2990 	         gpointer pass_not_needed_data,
2991 		 gint8 *exit_status,
2992 	         GError **error)
2993 {
2994   GConfClient *gconf_client;
2995   gboolean sudo_mode;
2996 
2997   gconf_client = gconf_client_get_default ();
2998   sudo_mode = gconf_client_get_bool (gconf_client, BASE_PATH "sudo-mode",
2999 				     NULL);
3000   g_object_unref (gconf_client);
3001 
3002   if (sudo_mode)
3003     return gksu_sudo_fuller (context, ask_pass, ask_pass_data,
3004 			     pass_not_needed, pass_not_needed_data,
3005 			     exit_status, error);
3006 
3007   return gksu_su_fuller (context, ask_pass, ask_pass_data,
3008 		         pass_not_needed, pass_not_needed_data,
3009 		         exit_status, error);
3010 }
3011 
3012 /**
3013  * gksu_run
3014  * @command_line: the command line that will be executed as other user
3015  * @error: a #GError to be set with the error condition, if an error
3016  * happens
3017  *
3018  * This function is a wrapper for gksu_sudo/gksu_su. It will call one
3019  * of them, depending on the GConf key that defines whether the default
3020  * behavior for gksu is su or sudo mode. This is the recommended way of
3021  * using the library functionality.
3022  *
3023  * Returns: FALSE if all went well, TRUE if an error happend.
3024  */
3025 gboolean
gksu_run(gchar * command_line,GError ** error)3026 gksu_run (gchar *command_line,
3027 	  GError **error)
3028 {
3029   GConfClient *gconf_client;
3030   gboolean sudo_mode;
3031 
3032   gconf_client = gconf_client_get_default ();
3033   sudo_mode = gconf_client_get_bool (gconf_client, BASE_PATH "sudo-mode",
3034 				     NULL);
3035   g_object_unref (gconf_client);
3036 
3037   if (sudo_mode)
3038     return gksu_sudo (command_line, error);
3039 
3040   return gksu_su (command_line, error);
3041 }
3042 
3043 /**
3044  * gksu_ask_password_full:
3045  * @context: a #GksuContext
3046  * @prompt: a prompt different from Password:
3047  * @error: a #GError object to be filled with the error code or NULL
3048  *
3049  * This function uses the gksu infra-structure to request for a
3050  * password, but instead of passing it to su or sudo to run a command
3051  * it simply returns the password.
3052  *
3053  * Returns: a newly allocated string with the password;
3054  */
3055 gchar*
gksu_ask_password_full(GksuContext * context,gchar * prompt,GError ** error)3056 gksu_ask_password_full (GksuContext *context, gchar *prompt,
3057 			GError **error)
3058 {
3059   gchar *ret_value = su_ask_password (context, _(prompt), NULL, error);
3060   if (context->sn_context)
3061     gksu_context_launch_complete (context);
3062   return ret_value;
3063 }
3064 
3065 /**
3066  * gksu_ask_password
3067  * @error: a #GError to be set with the error condition, if an error
3068  * happens
3069  *
3070  * This function uses the gksu infra-structure to request for a
3071  * password, but instead of passing it to su or sudo to run a command
3072  * it simply returns the password. This is just a convenience wrapper
3073  * for gksu_ask_password_full.
3074  *
3075  * Returns: a newly allocated string with the password;
3076  */
3077 gchar*
gksu_ask_password(GError ** error)3078 gksu_ask_password (GError **error)
3079 {
3080   GksuContext *context = gksu_context_new ();
3081   gchar* retval;
3082 
3083   context->user = g_strdup ("root");
3084   retval = gksu_ask_password_full (context, NULL, error);
3085   gksu_context_free (context);
3086 
3087   return retval;
3088 }
3089