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 (¤t_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 (¤t_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