Re: [gdm-list] PoC for multiple pam prompts
- From: Ludwig Nussel <ludwig nussel suse de>
- To: gdm-list gnome org
- Subject: Re: [gdm-list] PoC for multiple pam prompts
- Date: Thu, 8 Feb 2007 17:10:54 +0100
Ludwig Nussel wrote:
> I've started to implement multiple pam prompts in gdmlogin. It looks
> like this[1]:
> http://www.suse.de/~lnussel/gdm/gdm1.png
> http://www.suse.de/~lnussel/gdm/gdm2.png
>
> The patch works but is not ready for production yet. gdmgreeter not
> supported yet. I post it here for discussion and for the brave for
> testing.
Updated patchs attached. gdmgreeter now at least works again with
serialized prompts.
cu
Ludwig
--
(o_ Ludwig Nussel
//\ SUSE LINUX Products GmbH, Development
V_/_ http://www.suse.de/
Index: gdm2/daemon/gdm.h
===================================================================
--- gdm2.orig/daemon/gdm.h
+++ gdm2/daemon/gdm.h
@@ -31,6 +31,7 @@
* leaves MAX_PASS undefined. */
#define STX 0x2 /* Start of txt */
+#define EOX 0x3 /* End of txt */
#define BEL 0x7 /* Bell, used to interrupt login for
* say timed login or something similar */
@@ -91,8 +92,9 @@ enum {
/* This will change if there are incompatible
* protocol changes */
-#define GDM_GREETER_PROTOCOL_VERSION "3"
+#define GDM_GREETER_PROTOCOL_VERSION "4"
+#define GDM_PAM_FORM 'p'
#define GDM_MSG 'D'
#define GDM_NOECHO 'U'
#define GDM_PROMPT 'N'
Index: gdm2/daemon/slave.c
===================================================================
--- gdm2.orig/daemon/slave.c
+++ gdm2/daemon/slave.c
@@ -95,6 +95,8 @@
#include "gdmconsolekit.h"
#endif
+#define dbg(fmt, args...) gdm_info("%s:%d %s() - " fmt "\n", __FILE__, __LINE__, __FUNCTION__, ##args)
+
/* Some per slave globals */
static GdmDisplay *d = 0;
static gchar *login = NULL;
@@ -1995,10 +1997,12 @@ gdm_slave_wait_for_login (void)
g_free (login);
login = NULL;
/* clear any error */
+#if 0
gdm_slave_greeter_ctl_no_ret (GDM_ERRBOX, "");
gdm_slave_greeter_ctl_no_ret
(GDM_MSG,
_("You must authenticate as root to run configuration."));
+#endif
/* we always allow root for this */
oldAllowRoot = gdm_get_value_bool (GDM_KEY_ALLOW_ROOT);
@@ -2018,8 +2022,10 @@ gdm_slave_wait_for_login (void)
d->attached);
gdm_set_value_bool (GDM_KEY_ALLOW_ROOT, oldAllowRoot);
+#if 0
/* Clear message */
gdm_slave_greeter_ctl_no_ret (GDM_MSG, "");
+#endif
if G_UNLIKELY (do_restart_greeter) {
g_free (login);
@@ -5127,7 +5133,6 @@ check_for_interruption (const char *msg)
return FALSE;
}
-
char *
gdm_slave_greeter_ctl (char cmd, const char *str)
{
@@ -5170,6 +5175,8 @@ gdm_slave_greeter_ctl (char cmd, const c
/* user responses take kind of random amount of time */
gdm_random_tick ();
+ dbg("%c%s -> %s", cmd, str, buf);
+
if ( ! ve_string_empty (buf)) {
return buf;
} else {
Index: gdm2/daemon/verify-pam.c
===================================================================
--- gdm2.orig/daemon/verify-pam.c
+++ gdm2/daemon/verify-pam.c
@@ -47,6 +47,16 @@
#include <bsm/adt_event.h>
#endif /* HAVE_ADT */
+#define dbg(fmt, args...) gdm_info("%s:%d %s() - " fmt "\n", __FILE__, __LINE__, __FUNCTION__, ##args)
+#if 0
+#define gdm_slave_greeter_ctl_no_ret(op, msg) gdm_slave_greeter_ctl_no_ret(op, msg); dbg("sent %c %s", op, msg)
+#define gdm_slave_greeter_ctl(op, msg) gdm_slave_greeter_ctl(op, msg); dbg("sent %c %s", op, msg)
+#endif
+#if 1
+#define openlog(a,b,c)
+#define closelog()
+#endif
+
/* Evil, but this way these things are passed to the child session */
static pam_handle_t *pamh = NULL;
@@ -66,6 +76,10 @@ static char *selected_user = NULL;
static gboolean opened_session = FALSE;
static gboolean did_setcred = FALSE;
+/* used if there is a problem in a conversation to abort also all
+ * following as they cannot succeed anymore anyways */
+static gboolean abort_conversations;
+
extern char *gdm_ack_question_response;
#ifdef HAVE_ADT
@@ -474,6 +488,18 @@ perhaps_translate_message (const char *m
/* Internal PAM conversation function. Interfaces between the PAM
* authentication system and the actual greeter program */
+static inline char msg_style2gdm(int msg_style)
+{
+ switch (msg_style) {
+ case PAM_PROMPT_ECHO_ON: return GDM_PROMPT;
+ case PAM_PROMPT_ECHO_OFF: return GDM_NOECHO;
+ case PAM_ERROR_MSG: return GDM_ERRBOX;
+ case PAM_TEXT_INFO: return GDM_MSG;
+ }
+ gdm_assert_not_reached();
+ return 0;
+}
+
static int
gdm_verify_pam_conv (int num_msg, const struct pam_message **msg,
struct pam_response **resp,
@@ -482,10 +508,17 @@ gdm_verify_pam_conv (int num_msg, const
int replies = 0;
int i;
char *s = NULL;
+ char* str = NULL;
+ size_t sendbuflen = 0;
struct pam_response *reply = NULL;
const void *p;
const char *login;
+ dbg("num_msg %d", num_msg);
+
+ if(!num_msg) /* weird */
+ return PAM_SUCCESS;
+
if (pamh == NULL)
return PAM_CONV_ERR;
@@ -494,21 +527,15 @@ gdm_verify_pam_conv (int num_msg, const
maybe it will listen */
/* well, it actually happens if there are multiple pam modules
* with conversations */
- if ( ! gdm_slave_action_pending () || selected_user)
+ if ( abort_conversations || ! gdm_slave_action_pending () || selected_user)
return PAM_CONV_ERR;
- reply = malloc (sizeof (struct pam_response) * num_msg);
-
- if (reply == NULL)
- return PAM_CONV_ERR;
-
- memset (reply, 0, sizeof (struct pam_response) * num_msg);
-
/* Here we set the login if it wasn't already set,
* this is kind of anal, but this way we guarantee that
* the greeter always is up to date on the login */
if (pam_get_item (pamh, PAM_USER, &p) == PAM_SUCCESS) {
- login = (const char *)p;
+ login = (const char *)p;
+ if(login)
gdm_slave_greeter_ctl_no_ret (GDM_SETLOGIN, login);
}
@@ -516,88 +543,111 @@ gdm_verify_pam_conv (int num_msg, const
closelog ();
openlog ("gdm", LOG_PID, LOG_DAEMON);
+ if (gdm_slave_greeter_check_interruption ()) {
+ gdm_fail("unexpected interruption in pam conversation");
+ return PAM_CONV_ERR;
+ }
+
+ /* check for valid form first */
+ if(num_msg > 255-'\n') {
+ gdm_error("too many prompts");
+ return PAM_CONV_ERR;
+ }
+ sendbuflen = 1 /* num_msg */;
for (replies = 0; replies < num_msg; replies++) {
- const char *m = (*msg)[replies].msg;
- m = perhaps_translate_message (m);
-
switch ((*msg)[replies].msg_style) {
-
- /* PAM requested textual input with echo on */
- case PAM_PROMPT_ECHO_ON:
- if (strcmp (m, _("Username:")) == 0) {
- if ( ve_string_empty (selected_user)) {
- /* this is an evil hack, but really there is no way we'll
- know this is a username prompt. However we SHOULD NOT
- rely on this working. The pam modules can set their
- prompt to whatever they wish to */
- gdm_slave_greeter_ctl_no_ret
- (GDM_MSG, _("Please enter your username"));
- s = gdm_slave_greeter_ctl (GDM_PROMPT, m);
- /* this will clear the message */
- gdm_slave_greeter_ctl_no_ret (GDM_MSG, "");
+ case PAM_PROMPT_ECHO_OFF:
+ case PAM_PROMPT_ECHO_ON:
+ case PAM_ERROR_MSG:
+ case PAM_TEXT_INFO:
+ {
+ const char *m = (*msg)[replies].msg;
+ size_t len;
+ m = perhaps_translate_message (m);
+ len = strlen(m);
+ if(len > 255-'\n') {
+ gdm_error("pam prompt too long");
+ return PAM_CONV_ERR;
}
- } else {
- s = gdm_slave_greeter_ctl (GDM_PROMPT, m);
- }
+ if (!len) len = 1;
+ sendbuflen += 1 /* type */ + len + 1 /* \0 */;
+ }
+ break;
+ default:
+ return PAM_CONV_ERR;
+ }
+ }
- if (gdm_slave_greeter_check_interruption ()) {
- g_free (s);
- for (i = 0; i < replies; i++)
- if (reply[replies].resp != NULL)
- free (reply[replies].resp);
- free (reply);
- return PAM_CONV_ERR;
- }
+ s = str = malloc(sendbuflen);
- reply[replies].resp_retcode = PAM_SUCCESS;
- reply[replies].resp = strdup (ve_sure_string (s));
- g_free (s);
- break;
-
- case PAM_PROMPT_ECHO_OFF:
- if (strcmp (m, _("Password:")) == 0)
- did_we_ask_for_password = TRUE;
- /* PAM requested textual input with echo off */
- s = gdm_slave_greeter_ctl (GDM_NOECHO, m);
- if (gdm_slave_greeter_check_interruption ()) {
- g_free (s);
- for (i = 0; i < replies; i++)
- if (reply[replies].resp != NULL)
- free (reply[replies].resp);
- free (reply);
- return PAM_CONV_ERR;
- }
- reply[replies].resp_retcode = PAM_SUCCESS;
- reply[replies].resp = strdup (ve_sure_string (s));
- g_free (s);
- break;
-
- case PAM_ERROR_MSG:
- /* PAM sent a message that should displayed to the user */
- gdm_slave_greeter_ctl_no_ret (GDM_ERRDLG, m);
- reply[replies].resp_retcode = PAM_SUCCESS;
- reply[replies].resp = NULL;
- break;
- case PAM_TEXT_INFO:
- /* PAM sent a message that should displayed to the user */
- gdm_slave_greeter_ctl_no_ret (GDM_MSG, m);
- reply[replies].resp_retcode = PAM_SUCCESS;
- reply[replies].resp = NULL;
- break;
-
- default:
- /* PAM has been smoking serious crack */
- for (i = 0; i < replies; i++)
- if (reply[replies].resp != NULL)
- free (reply[replies].resp);
- free (reply);
- return PAM_CONV_ERR;
- }
+ /* prevent low values from beeing interpreted as control chars */
+ *s++ = num_msg + '\n';
+
+ for (replies = 0; replies < num_msg; replies++) {
+
+ const char *m = (*msg)[replies].msg;
+ m = perhaps_translate_message (m);
+ m = ve_sure_string(m);
+ *s++ = msg_style2gdm((*msg)[replies].msg_style);
+ strcpy(s, m);
+ // XXX: remove EOX from string
+ s[strlen(m)] = EOX;
+ s += strlen(m)+1;
+ }
+
+ s = gdm_slave_greeter_ctl(GDM_PAM_FORM, str);
+
+ if (gdm_slave_greeter_check_interruption ()) {
+ g_free(s);
+ goto error;
+ }
+
+ if(!s || s[0] == '\n')
+ {
+ g_free(s);
+ gdm_error("empty reply from greeter");
+ goto error;
+ }
+
+ free(str);
+ str = s;
+
+ reply = malloc (sizeof (struct pam_response) * num_msg);
+
+ if (reply == NULL)
+ return PAM_CONV_ERR;
+
+ memset (reply, 0, sizeof (struct pam_response) * num_msg);
+
+ for (replies = 0; replies < num_msg; ++replies) {
+ char* eos = strchr(s, EOX);
+ if(!eos || !s[0] || s[0] == '\n') {
+ gdm_error("invalid reply from greeter");
+ goto error;
+ }
+ *eos = '\0';
+ dbg("< %d %s", replies, s);
+ reply[replies].resp = strdup(s);
+ reply[replies].resp_retcode = PAM_SUCCESS;
+ s = eos + 1;
}
*resp = reply;
return PAM_SUCCESS;
+
+error:
+ if(reply)
+ for (i = 0; i < replies; ++i)
+ if (reply[replies].resp != NULL)
+ free (reply[replies].resp);
+
+ free (reply);
+ free(str);
+
+ abort_conversations = TRUE;
+
+ return PAM_CONV_ERR;
}
@@ -902,6 +952,7 @@ authenticate_again:
/* Start authentication session */
did_we_ask_for_password = FALSE;
+ abort_conversations = FALSE;
if ((pamerr = pam_authenticate (pamh, null_tok)) != PAM_SUCCESS) {
if ( ! ve_string_empty (selected_user)) {
pam_handle_t *tmp_pamh;
@@ -996,6 +1047,14 @@ authenticate_again:
goto pamerr;
}
+ if(!p) {
+ /* huh? pam modules forgot to ask for the user */
+ pamerr = PAM_PERM_DENIED;
+ if (gdm_slave_action_pending ())
+ gdm_error ("PAM_USER unset after pam conversation");
+ goto pamerr;
+ }
+
login = g_strdup ((const char *)p);
/* kind of anal, the greeter likely already knows, but it could have
been changed */
@@ -1196,7 +1255,11 @@ authenticate_again:
} else {
msg = g_strdup (basemsg);
}
- gdm_slave_greeter_ctl_no_ret (GDM_ERRBOX, msg);
+ gdm_slave_greeter_ctl_no_ret (GDM_ERRDLG, msg);
+ g_free (msg);
+ } else if (pamh) {
+ char* msg = g_strdup_printf( _("Authentication failed:\n%s"), pam_strerror(pamh, pamerr));
+ gdm_slave_greeter_ctl_no_ret (GDM_ERRDLG, msg);
g_free (msg);
} else {
gdm_slave_greeter_ctl_no_ret (GDM_ERRDLG, _("Authentication failed"));
Index: gdm2/gui/gdmlogin.c
===================================================================
--- gdm2.orig/gui/gdmlogin.c
+++ gdm2/gui/gdmlogin.c
@@ -61,8 +61,11 @@
#include "gdmwm.h"
#include "gdmlanguages.h"
#include "gdmconfig.h"
+#include "gdmpamform.h"
#include "misc.h"
+#define dbg(fmt, args...) do { gdm_common_info("%s:%d %s() - " fmt, __FILE__, __LINE__, __FUNCTION__, ##args); } while(0)
+
/* set the DOING_GDM_DEVELOPMENT env variable if you aren't running
* within the protocol */
static gboolean DOING_GDM_DEVELOPMENT = FALSE;
@@ -96,21 +99,18 @@ static GtkWidget *logo_image = NULL;
static GtkWidget *table = NULL;
static GtkWidget *welcome;
static GtkWidget *title;
-static GtkWidget *label;
static GtkWidget *icon_button = NULL;
static GtkWidget *title_box = NULL;
static GtkWidget *clock_label = NULL;
-static GtkWidget *entry;
+static GtkWidget *gui_form_vbox;
static GtkWidget *ok_button;
static GtkWidget *start_again_button;
-static GtkWidget *msg;
static GtkWidget *auto_timed_msg;
-static GtkWidget *err_box;
-static guint err_box_clear_handler = 0;
static gboolean require_quarter = FALSE;
static GtkWidget *icon_win = NULL;
static GtkWidget *sessmenu;
static GtkWidget *langmenu;
+static GtkWidget *statusbar;
static gboolean login_is_local = FALSE;
@@ -149,6 +149,11 @@ static gboolean back_prog_delayed = FALS
static guint timed_handler_id = 0;
+PamForm pam_form[256-'\n'] = {{0, NULL, NULL}};
+unsigned num_pam_form;
+
+GtkWidget* pam_form_vbox = NULL;
+
#if FIXME
static char *selected_browser_user = NULL;
#endif
@@ -179,8 +184,18 @@ static void back_prog_launch_after_timeo
static void back_prog_run (void);
static void back_prog_stop (void);
+static void gui_process_form(void);
static void process_operation (guchar op_code, const gchar *args);
+static gboolean pop_statusbar (gpointer data);
+static void update_statusbar_timeout (const char* text);
+static void update_statusbar (const char* text);
+static guint statusbar_timeout_id;
+
+
+static gboolean username_prompt_focus_in(GtkWidget *widget, GdkEventFocus *event);
+static gboolean username_prompt_focus_out (GtkWidget *widget, GdkEventFocus *event);
+
/*
* This function is called when the background program exits.
* It will add a timer to restart the program after the
@@ -522,6 +537,7 @@ gdm_event (GSignalInvocationHint *ihint,
&& event->button.button == 3)
event->button.button = 1;
+#if 0
/* Support Ctrl-U for blanking the username/password entry */
if (event->type == GDK_KEY_PRESS &&
(event->key.state & GDK_CONTROL_MASK) &&
@@ -530,6 +546,7 @@ gdm_event (GSignalInvocationHint *ihint,
gtk_entry_set_text (GTK_ENTRY (entry), "");
}
+#endif
return TRUE;
}
@@ -839,9 +856,15 @@ dance (gpointer data)
}
static gboolean
-evil (const char *user)
+evil (GtkWidget* entry)
{
static gboolean old_lock;
+ const char* user;
+
+ if(!GTK_IS_ENTRY(entry))
+ return FALSE;
+
+ user = gtk_entry_get_text (GTK_ENTRY (entry));
if (dance_handler == 0 &&
/* do not translate */
@@ -882,6 +905,18 @@ evil (const char *user)
return FALSE;
}
+static gboolean
+gdm_evil_handler_pressed (GtkWidget *widget, GdkEventKey *event, gpointer data)
+{
+ if (event->keyval == GDK_Return
+ && (event->state & (GDK_CONTROL_MASK|GDK_MOD1_MASK|GDK_SHIFT_MASK)) == 0) {
+ return evil(widget);
+ }
+
+ return FALSE;
+}
+
+#if 0
static void
gdm_login_enter (GtkWidget *entry)
{
@@ -937,16 +972,45 @@ gdm_login_enter (GtkWidget *entry)
fflush (stdout);
g_free (tmp);
}
+#endif
static void
gdm_login_ok_button_press (GtkButton *button, GtkWidget *entry)
{
- gdm_login_enter (entry);
+ unsigned i;
+
+ dbg("%d form items", num_pam_form);
+ fputc(STX, stdout);
+ for(i = 0; i < num_pam_form; ++i) {
+ char* s = NULL;
+ switch(pam_form[i].style) {
+ case GDM_NOECHO:
+ case GDM_PROMPT:
+ s = ve_locale_from_utf8(gtk_entry_get_text(GTK_ENTRY(pam_form[i].widget)));
+ }
+ if(pam_form[i].widget)
+ gtk_widget_set_sensitive(GTK_WIDGET(pam_form[i].widget), FALSE);
+ dbg("-> %d %d %s", i, pam_form[i].style, s);
+ fputs(ve_sure_string(s), stdout);
+ fputc(EOX, stdout);
+ g_free(s);
+ }
+ fputc('\n', stdout);
+ fflush (stdout);
+
+#if 0
+ /* don't do that to prevent resizes */
+ gtk_container_remove(GTK_CONTAINER(gui_form_vbox), pam_form_vbox);
+ pam_form_vbox = NULL;
+#endif
+
+ dbg("OK!");
}
static void
-gdm_login_start_again_button_press (GtkButton *button, GtkWidget *entry)
+gdm_login_start_again_button_press (GtkButton *button, gpointer data)
{
+ unsigned i;
GtkTreeSelection *selection;
if (browser != NULL) {
@@ -958,6 +1022,18 @@ gdm_login_start_again_button_press (GtkB
g_free (selected_user);
selected_user = NULL;
+ for(i = 0; i < num_pam_form; ++i) {
+ if(pam_form[i].widget)
+ gtk_widget_set_sensitive(GTK_WIDGET(pam_form[i].widget), FALSE);
+ }
+#if 0
+ /* don't do that to prevent resizes */
+ gtk_container_remove(GTK_CONTAINER(gui_form_vbox), pam_form_vbox);
+ pam_form_vbox = NULL;
+#endif
+
+ gtk_widget_set_sensitive (ok_button, FALSE);
+
printf ("%c%c%c\n", STX, BEL,
GDM_INTERRUPT_CANCEL);
fflush (stdout);
@@ -984,6 +1060,57 @@ gdm_login_focus_out (GtkWidget *widget,
return FALSE;
}
+static gboolean
+username_prompt_focus_in(GtkWidget *widget, GdkEventFocus *event)
+{
+ update_statusbar(_("Please enter your username"));
+ return FALSE;
+}
+
+static gboolean
+username_prompt_focus_out (GtkWidget *widget, GdkEventFocus *event)
+{
+ update_statusbar(NULL);
+ return FALSE;
+}
+
+static gboolean
+pop_statusbar(gpointer data)
+{
+ guint id = GPOINTER_TO_INT(data);
+ gtk_statusbar_pop(GTK_STATUSBAR(statusbar), id);
+ return TRUE;
+}
+
+static void update_statusbar_timeout (const char* text)
+{
+ guint id = gtk_statusbar_get_context_id(GTK_STATUSBAR(statusbar), "timeout");
+
+ gtk_statusbar_pop(GTK_STATUSBAR(statusbar), id);
+
+ if(!text)
+ return;
+
+ gtk_statusbar_push(GTK_STATUSBAR(statusbar), id, text);
+
+ if(statusbar_timeout_id)
+ g_source_remove (statusbar_timeout_id);
+
+ statusbar_timeout_id = g_timeout_add (5000, pop_statusbar, GINT_TO_POINTER(id));
+}
+
+static void update_statusbar(const char* text)
+{
+ guint id = gtk_statusbar_get_context_id(GTK_STATUSBAR(statusbar), "static");
+
+ gtk_statusbar_pop(GTK_STATUSBAR(statusbar), id);
+
+ if(!text)
+ return;
+
+ gtk_statusbar_push(GTK_STATUSBAR(statusbar), id, text);
+}
+
static void
gdm_login_session_handler (GtkWidget *widget)
{
@@ -993,7 +1120,8 @@ gdm_login_session_handler (GtkWidget *wi
s = g_strdup_printf (_("%s session selected"), gdm_session_name (current_session));
- gtk_label_set_text (GTK_LABEL (msg), s);
+ update_statusbar_timeout(s);
+
g_free (s);
login_window_resize (FALSE /* force */);
@@ -1097,7 +1225,7 @@ gdm_login_language_handler (GtkWidget *w
TRUE /* makrup */);
s = g_strdup_printf (_("%s language selected"), name);
g_free (name);
- gtk_label_set_markup (GTK_LABEL (msg), s);
+ update_statusbar_timeout(s);
g_free (s);
login_window_resize (FALSE /* force */);
@@ -1375,6 +1503,7 @@ gdm_login_theme_menu_new (void)
return menu;
}
+#if 0
static gboolean
err_box_clear (gpointer data)
{
@@ -1384,6 +1513,7 @@ err_box_clear (gpointer data)
err_box_clear_handler = 0;
return FALSE;
}
+#endif
static void
browser_set_user (const char *user)
@@ -1393,6 +1523,8 @@ browser_set_user (const char *user)
GtkTreeIter iter = {0};
GtkTreeModel *tm = NULL;
+ dbg("%s %s", __FUNCTION__, user);
+
if (browser == NULL)
return;
@@ -1525,6 +1657,153 @@ gdm_login_ctrl_handler (GIOChannel *sour
return TRUE;
}
+static void gui_process_form(void)
+{
+ int i;
+ int firstentry = -1;
+ GtkWidget* preventry = NULL;
+
+ dbg("num_pam_form %d", num_pam_form);
+
+ if(pam_form_vbox)
+ gtk_container_remove(GTK_CONTAINER(gui_form_vbox), pam_form_vbox);
+
+ pam_form_vbox = gtk_vbox_new(FALSE, 0);
+
+ for (i = 0; i < num_pam_form; ++i)
+ {
+ unsigned style = pam_form[i].style;
+ char* msg = ve_locale_to_utf8(pam_form[i].msg);
+
+ dbg("%c %s", style, msg);
+
+ switch(style)
+ {
+ case GDM_NOECHO:
+ case GDM_PROMPT:
+ {
+ GtkWidget* hbox;
+ GtkWidget* label;
+ GtkWidget* entry;
+ gboolean is_username;
+
+ if((is_username = !strcmp(msg, _("Username:"))))
+ msg = _("_Username:");
+
+ hbox = gtk_hbox_new(FALSE, 4);
+ label = gtk_label_new_with_mnemonic(msg);
+ pam_form[i].widget = entry = gtk_entry_new();
+ gtk_widget_set_size_request (entry, 200, -1);
+
+ gtk_entry_set_max_length (GTK_ENTRY (entry), PW_ENTRY_SIZE);
+ gtk_entry_set_visibility(GTK_ENTRY(entry), (style == GDM_PROMPT));
+
+ gdm_common_setup_blinking_entry (entry);
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
+
+ gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, TRUE, 0);
+
+ gtk_box_pack_start(GTK_BOX(pam_form_vbox), hbox, TRUE, TRUE, 0);
+
+ if(firstentry == -1)
+ firstentry = i;
+
+ if(is_username)
+ {
+ msg = NULL; // static string from gettext, prevent g_free()
+
+ if(selected_user)
+ gtk_entry_set_text (GTK_ENTRY(entry), selected_user);
+
+ /* TODO: set callback for evil() */
+
+ g_signal_connect (G_OBJECT (entry), "focus_in_event",
+ G_CALLBACK (username_prompt_focus_in),
+ NULL);
+ g_signal_connect (G_OBJECT (entry), "focus_out_event",
+ G_CALLBACK (username_prompt_focus_out),
+ NULL);
+
+ g_signal_connect (G_OBJECT (entry), "key_press_event",
+ G_CALLBACK (gdm_evil_handler_pressed), NULL);
+
+ gdm_common_login_sound (gdm_config_get_string (GDM_KEY_SOUND_PROGRAM),
+ gdm_config_get_string (GDM_KEY_SOUND_ON_LOGIN_FILE),
+ gdm_config_get_bool (GDM_KEY_SOUND_ON_LOGIN));
+ }
+
+ if(preventry)
+ {
+ g_signal_connect_swapped((gpointer)preventry, "activate",
+ G_CALLBACK(gtk_widget_grab_focus),
+ entry);
+ }
+
+ preventry = entry;
+
+ } break;
+ case GDM_MSG:
+ case GDM_ERRBOX:
+ {
+ GtkWidget* hbox;
+ GtkWidget* label;
+ GtkWidget* icon;
+
+ hbox = gtk_hbox_new(FALSE, 0);
+ label = gtk_label_new(msg);
+
+ gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+
+ if(style == GDM_ERRBOX)
+ icon = gtk_image_new_from_stock(
+ GTK_STOCK_DIALOG_ERROR,
+ GTK_ICON_SIZE_BUTTON);
+ else
+ icon = gtk_image_new_from_stock(
+ GTK_STOCK_DIALOG_INFO,
+ GTK_ICON_SIZE_BUTTON);
+
+ gtk_box_pack_start(GTK_BOX(hbox), icon, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+
+ gtk_box_pack_start(GTK_BOX(pam_form_vbox), hbox, TRUE, TRUE, 2);
+
+ } break;
+ }
+
+ g_free(msg);
+ }
+
+ gtk_widget_show_all(pam_form_vbox);
+
+ gtk_box_pack_start(GTK_BOX(gui_form_vbox), pam_form_vbox, TRUE, TRUE, 0);
+ gtk_box_reorder_child(GTK_BOX(gui_form_vbox), pam_form_vbox, 1);
+
+ if(firstentry != -1)
+ {
+ gtk_widget_grab_focus(pam_form[firstentry].widget);
+ }
+ else
+ {
+ gtk_widget_grab_focus(ok_button);
+ }
+
+ // enter in last entry behaves like klicking the ok button
+ if(preventry)
+ {
+ g_signal_connect_swapped((gpointer)preventry, "activate",
+ G_CALLBACK (gtk_button_clicked),
+ ok_button);
+ }
+
+ gtk_widget_set_sensitive (start_again_button, TRUE);
+ gtk_widget_set_sensitive (ok_button, TRUE);
+
+ login_window_resize(FALSE);
+}
+
static void
process_operation (guchar op_code,
const gchar *args)
@@ -1532,13 +1811,13 @@ process_operation (guchar op_code,
char *tmp;
gint i, x, y;
GtkWidget *dlg;
- static gboolean replace_msg = TRUE;
- static gboolean messages_to_give = FALSE;
gint lookup_status = SESSION_LOOKUP_SUCCESS;
gchar *firstmsg = NULL;
gchar *secondmsg = NULL;
gint save_session = GTK_RESPONSE_NO;
+ dbg("code %c", op_code);
+
/* Parse opcode */
switch (op_code) {
case GDM_SETLOGIN:
@@ -1551,7 +1830,27 @@ process_operation (guchar op_code,
printf ("%c\n", STX);
fflush (stdout);
break;
+
+ case GDM_PAM_FORM:
+
+ if(parse_form(args))
+ gui_process_form();
+ break;
+
+ case GDM_ERRBOX:
+ case GDM_MSG:
+ // TODO: check whether a form is already active and switch
+ // to dialog if so?
+ case GDM_PROMPT:
+ case GDM_NOECHO:
+ memset(pam_form, 0, sizeof(pam_form));
+ pam_form[0].style = op_code;
+ pam_form[0].msg = args;
+ num_pam_form = 1;
+ gui_process_form();
+ break;
+#if 0
case GDM_PROMPT:
tmp = ve_locale_to_utf8 (args);
if (tmp != NULL && strcmp (tmp, _("Username:")) == 0) {
@@ -1675,6 +1974,7 @@ process_operation (guchar op_code,
login_window_resize (FALSE /* force */);
break;
+#endif
case GDM_ERRDLG:
/* we should be now fine for focusing new windows */
@@ -1822,17 +2122,31 @@ process_operation (guchar op_code,
first_prompt = TRUE;
- gtk_widget_set_sensitive (entry, TRUE);
gtk_widget_set_sensitive (ok_button, FALSE);
gtk_widget_set_sensitive (start_again_button, FALSE);
+ gtk_container_remove(GTK_CONTAINER(gui_form_vbox), pam_form_vbox);
+ pam_form_vbox = NULL;
+ num_pam_form = 0;
+
if (browser_ok && gdm_config_get_bool (GDM_KEY_BROWSER))
gtk_widget_set_sensitive (GTK_WIDGET (browser), TRUE);
- tmp = ve_locale_to_utf8 (args);
- gtk_label_set_text (GTK_LABEL (msg), tmp);
- g_free (tmp);
- gtk_widget_show (GTK_WIDGET (msg));
+ if(!ve_string_empty(args)) {
+ tmp = ve_locale_to_utf8 (args);
+ dlg = ve_hig_dialog_new (NULL /* parent */,
+ GTK_DIALOG_MODAL /* flags */,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_OK,
+ "%s", tmp);
+ gdm_wm_center_window (GTK_WINDOW (dlg));
+
+ gdm_wm_no_login_focus_push ();
+ gtk_dialog_run (GTK_DIALOG (dlg));
+ gtk_widget_destroy (dlg);
+ gdm_wm_no_login_focus_pop ();
+ g_free (tmp);
+ }
printf ("%c\n", STX);
fflush (stdout);
@@ -1870,31 +2184,6 @@ process_operation (guchar op_code,
/* Hide the login window now */
gtk_widget_hide (login);
- if (messages_to_give) {
- const char *oldtext;
- oldtext = gtk_label_get_text (GTK_LABEL (msg));
-
- if ( ! ve_string_empty (oldtext)) {
- /* we should be now fine for focusing new windows */
- gdm_wm_focus_new_windows (TRUE);
-
- dlg = ve_hig_dialog_new (NULL /* parent */,
- GTK_DIALOG_MODAL /* flags */,
- GTK_MESSAGE_INFO,
- GTK_BUTTONS_OK,
- oldtext,
- "");
- gtk_window_set_modal (GTK_WINDOW (dlg), TRUE);
- gdm_wm_center_window (GTK_WINDOW (dlg));
-
- gdm_wm_no_login_focus_push ();
- gtk_dialog_run (GTK_DIALOG (dlg));
- gtk_widget_destroy (dlg);
- gdm_wm_no_login_focus_pop ();
- }
- messages_to_give = FALSE;
- }
-
gdm_kill_thingies ();
gdk_flush ();
@@ -2047,15 +2336,8 @@ user_selected (GtkTreeSelection *selecti
char *login = NULL;
gtk_tree_model_get (tm, &iter, GREETER_ULIST_LOGIN_COLUMN,
&login, -1);
+ dbg("login %s selecting_user %d", login, selecting_user);
if (login != NULL) {
- const char *str = gtk_label_get_text (GTK_LABEL (label));
-
- if (selecting_user &&
- str != NULL &&
- (strcmp (str, _("Username:")) == 0 ||
- strcmp (str, _("_Username:")) == 0)) {
- gtk_entry_set_text (GTK_ENTRY (entry), login);
- }
#ifdef FIXME
selected_browser_user = g_strdup (login);
#endif
@@ -2069,12 +2351,6 @@ user_selected (GtkTreeSelection *selecti
}
}
-static void
-browser_change_focus (GtkWidget *widget, GdkEventButton *event, gpointer data)
-{
- gtk_widget_grab_focus (entry);
-}
-
static gboolean
gdm_login_handle_pressed (GtkWidget *widget, GdkEventButton *event)
{
@@ -2295,6 +2571,7 @@ window_browser_event (GtkWidget *window,
return FALSE;
}
+#if 0
static gboolean
key_release_event (GtkWidget *entry, GdkEventKey *event, gpointer data)
{
@@ -2307,6 +2584,7 @@ key_release_event (GtkWidget *entry, Gdk
return TRUE;
}
+#if 0 // don't try to be smart. maybe it's an optional entry field
/*
* Set ok button to sensitive only if there are characters in
* the entry field
@@ -2316,9 +2594,11 @@ key_release_event (GtkWidget *entry, Gdk
gtk_widget_set_sensitive (ok_button, TRUE);
else
gtk_widget_set_sensitive (ok_button, FALSE);
+#endif
return FALSE;
}
+#endif
static void
gdm_set_welcomemsg (void)
@@ -2343,7 +2623,7 @@ gdm_login_gui_init (void)
GtkTreeSelection *selection;
GtkWidget *frame1, *frame2, *ebox;
GtkWidget *mbox, *menu, *menubar, *item;
- GtkWidget *stack, *hline1, *hline2, *handle;
+ GtkWidget *handle;
GtkWidget *bbox = NULL;
GtkWidget /**help_button,*/ *button_box;
gint rows, i;
@@ -2584,10 +2864,6 @@ gdm_login_gui_init (void)
G_CALLBACK (user_selected),
NULL);
- g_signal_connect (browser, "button_release_event",
- G_CALLBACK (browser_change_focus),
- NULL);
-
browser_model = (GtkTreeModel *)gtk_list_store_new (3,
GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
@@ -2665,11 +2941,18 @@ gdm_login_gui_init (void)
gtk_widget_set_size_request (logo_image, lw, lh);
gtk_widget_show (GTK_WIDGET (logo_image));
+#if 0
stack = gtk_table_new (7, 1, FALSE);
gtk_widget_ref (stack);
g_object_set_data_full (G_OBJECT (login), "stack", stack,
(GDestroyNotify) gtk_widget_unref);
gtk_widget_show (stack);
+#endif
+
+ gui_form_vbox = gtk_vbox_new(FALSE, 0);
+ g_object_set_data_full (G_OBJECT (login), "gui_form_vbox", gui_form_vbox,
+ (GDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (gui_form_vbox);
/* Welcome msg */
welcome = gtk_label_new (NULL);
@@ -2679,10 +2962,15 @@ gdm_login_gui_init (void)
g_object_set_data_full (G_OBJECT (login), "welcome", welcome,
(GDestroyNotify) gtk_widget_unref);
gtk_widget_show (welcome);
+#if 0
gtk_table_attach (GTK_TABLE (stack), welcome, 0, 1, 0, 1,
(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
(GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 15);
+#endif
+ gtk_box_pack_start(GTK_BOX(gui_form_vbox), welcome, TRUE, TRUE, 0);
+
+#if 0
/* Put in error box here */
err_box = gtk_label_new (NULL);
gtk_widget_set_name (err_box, "Error box");
@@ -2767,14 +3055,21 @@ gdm_login_gui_init (void)
g_object_set_data_full (G_OBJECT (login), "msg", msg,
(GDestroyNotify) gtk_widget_unref);
gtk_widget_show (msg);
+#endif
+
+ /* cursor blinking is evil on remote displays, don't do it forever */
+ gdm_common_setup_blinking ();
auto_timed_msg = gtk_label_new ("");
gtk_widget_set_name (auto_timed_msg, "Message");
gtk_label_set_line_wrap (GTK_LABEL (auto_timed_msg), TRUE);
gtk_label_set_justify (GTK_LABEL (auto_timed_msg), GTK_JUSTIFY_LEFT);
+#if 0
gtk_table_attach (GTK_TABLE (stack), auto_timed_msg, 0, 1, 7, 8,
(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
(GtkAttachOptions) (GTK_FILL), 0, 10);
+#endif
+ gtk_box_pack_start(GTK_BOX(gui_form_vbox), auto_timed_msg, TRUE, TRUE, 0);
gtk_widget_set_size_request (auto_timed_msg, -1, 15);
gtk_widget_ref (auto_timed_msg);
@@ -2786,17 +3081,16 @@ gdm_login_gui_init (void)
gtk_widget_show (help_button);*/
ok_button = gtk_button_new_from_stock (GTK_STOCK_OK);
- GTK_WIDGET_UNSET_FLAGS (ok_button, GTK_CAN_FOCUS);
g_signal_connect (G_OBJECT (ok_button), "clicked",
G_CALLBACK (gdm_login_ok_button_press),
- entry);
+ NULL);
gtk_widget_show (ok_button);
start_again_button = gtk_button_new_with_mnemonic (_("_Start Again"));
GTK_WIDGET_UNSET_FLAGS (start_again_button, GTK_CAN_FOCUS);
g_signal_connect (G_OBJECT (start_again_button), "clicked",
G_CALLBACK (gdm_login_start_again_button_press),
- entry);
+ /* entry */ NULL);
gtk_widget_show (start_again_button);
button_box = gtk_hbutton_box_new ();
@@ -2816,9 +3110,12 @@ gdm_login_gui_init (void)
FALSE, TRUE, 0);
gtk_widget_show (button_box);
+#if 0
gtk_table_attach (GTK_TABLE (stack), button_box, 0, 1, 8, 9,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (GTK_FILL), 10, 10);
+#endif
+ gtk_box_pack_start(GTK_BOX(gui_form_vbox), button_box, TRUE, TRUE, 0);
/* Put it nicely together */
@@ -2829,20 +3126,22 @@ gdm_login_gui_init (void)
gtk_table_attach (GTK_TABLE (table), logo_frame, 0, 1, 1, 2,
(GtkAttachOptions) (GTK_FILL),
(GtkAttachOptions) (GTK_FILL), 0, 0);
- gtk_table_attach (GTK_TABLE (table), stack, 1, 2, 1, 2,
+ gtk_table_attach (GTK_TABLE (table), gui_form_vbox, 1, 2, 1, 2,
(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
(GtkAttachOptions) (GTK_FILL), 0, 0);
} else {
gtk_table_attach (GTK_TABLE (table), logo_frame, 0, 1, 0, 1,
(GtkAttachOptions) (0),
(GtkAttachOptions) (GTK_FILL), 0, 0);
- gtk_table_attach (GTK_TABLE (table), stack, 1, 2, 0, 1,
+ gtk_table_attach (GTK_TABLE (table), gui_form_vbox, 1, 2, 0, 1,
(GtkAttachOptions) (0),
(GtkAttachOptions) (GTK_FILL), 0, 0);
}
+
+ statusbar = gtk_statusbar_new();
+ gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(statusbar), FALSE);
+ gtk_box_pack_start (GTK_BOX (mbox), statusbar, TRUE, TRUE, 0);
- gtk_widget_grab_focus (entry);
- gtk_window_set_focus (GTK_WINDOW (login), entry);
g_object_set (G_OBJECT (login),
"allow_grow", TRUE,
"allow_shrink", TRUE,
@@ -2863,11 +3162,8 @@ gdm_login_gui_init (void)
G_CALLBACK (gdm_login_focus_out),
NULL);
- gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
-
/* normally disable the prompt first */
if ( ! DOING_GDM_DEVELOPMENT) {
- gtk_widget_set_sensitive (entry, FALSE);
gtk_widget_set_sensitive (ok_button, FALSE);
gtk_widget_set_sensitive (start_again_button, FALSE);
}
@@ -3392,6 +3688,9 @@ main (int argc, char *argv[])
gtk_init (&argc, &argv);
+ /* AHHH, much better now! the clueless won't notice anyways */
+ gtk_rc_parse_string("gtk-key-theme-name = \"Emacs\"");
+
if (ve_string_empty (g_getenv ("GDM_IS_LOCAL")))
disable_sys_config_chooser_buttons = TRUE;
Index: gdm2/gui/gdmuser.c
===================================================================
--- gdm2.orig/gui/gdmuser.c
+++ gdm2/gui/gdmuser.c
@@ -34,6 +34,10 @@
#include "gdmuser.h"
#include "gdmconfig.h"
+#define dbg(fmt, args...) do { gdm_common_info("%s:%d %s() - " fmt, __FILE__, __LINE__, __FUNCTION__, ##args); } while(0)
+#undef printf
+#define printf(fmt, args...) do { dbg("send " fmt, ##args); printf(fmt, ##args); } while(0)
+
static time_t time_started;
static GdmUser *
@@ -332,6 +336,8 @@ gdm_users_init (GList **users,
gboolean found_include = FALSE;
int i;
+ dbg("start");
+
time_started = time (NULL);
includes = g_strsplit (gdm_config_get_string (GDM_KEY_INCLUDE), ",", 0);
@@ -375,5 +381,7 @@ gdm_users_init (GList **users,
g_strfreev (includes);
g_strfreev (excludes);
+
+ dbg("done");
}
Index: gdm2/gui/Makefile.am
===================================================================
--- gdm2.orig/gui/Makefile.am
+++ gdm2/gui/Makefile.am
@@ -62,6 +62,8 @@ libgdmwm_a_SOURCES = \
gdmwm.h
libgdmcommon_a_SOURCES = \
+ gdmpamform.c \
+ gdmpamform.h \
gdmlanguages.c \
gdmlanguages.h \
gdmuser.c \
Index: gdm2/gui/gdmpamform.c
===================================================================
--- /dev/null
+++ gdm2/gui/gdmpamform.c
@@ -0,0 +1,68 @@
+/* GDM - The Gnome Display Manager
+ * Copyright (C) 2007 SUSE Linux Products GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "config.h"
+
+#include <gtk/gtk.h>
+
+#include "gdm.h"
+#include "gdmcommon.h"
+#include "gdmpamform.h"
+
+gboolean parse_form(const char* args)
+{
+ unsigned num_msg = *args++;
+ unsigned i = 0;
+
+ num_msg -= '\n';
+
+ memset(pam_form, 0, sizeof(pam_form));
+
+ while(i < num_msg)
+ {
+ unsigned style = *args++;
+ char* s = strchr(args, EOX);
+ if(!s) {
+ printf ("%c\n", STX);
+ fflush (stdout);
+ gdm_common_fail_greeter("invalid message in GDM_PAM_FORM");
+ return FALSE;
+ }
+ *s = '\0';
+ switch(style) {
+ case GDM_PROMPT:
+ case GDM_NOECHO:
+ case GDM_ERRBOX:
+ case GDM_MSG:
+ break;
+
+ default:
+ printf ("%c\n", STX);
+ fflush (stdout);
+ gdm_common_fail_greeter("Unexpected message type in GDM_PAM_FORM: 0x%hhx", style);
+ return FALSE;
+ }
+ pam_form[i].style = style;
+ pam_form[i].msg = args;
+ args += strlen(args)+1;
+ ++i;
+ }
+ num_pam_form = num_msg;
+
+ return TRUE;
+}
Index: gdm2/gui/gdmpamform.h
===================================================================
--- /dev/null
+++ gdm2/gui/gdmpamform.h
@@ -0,0 +1,35 @@
+/* GDM - The Gnome Display Manager
+ * Copyright (C) 2007 SUSE Linux Products GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef GDM_PAMFORM_H
+#define GDM_PAMFORM_H
+
+typedef struct {
+ unsigned style;
+ const char* msg;
+ GtkWidget* widget;
+} PamForm;
+
+extern PamForm pam_form[256-'\n']; /* can't have more than that anyways */
+extern unsigned num_pam_form;
+
+gboolean parse_form(const char* args);
+
+#endif /* GDM_PAMFORM_H */
+
+/* EOF */
Index: gdm2/gui/greeter/greeter.c
===================================================================
--- gdm2.orig/gui/greeter/greeter.c
+++ gdm2/gui/greeter/greeter.c
@@ -45,6 +45,7 @@
#include "gdmcommon.h"
#include "gdmconfig.h"
#include "gdmsession.h"
+#include "gdmpamform.h"
#include "greeter.h"
#include "greeter_configuration.h"
@@ -61,6 +62,8 @@
#include "greeter_session.h"
#include "greeter_system.h"
+#define dbg(fmt, args...) do { gdm_common_info("%s:%d %s() - " fmt, __FILE__, __LINE__, __FUNCTION__, ##args); } while(0)
+
gboolean DOING_GDM_DEVELOPMENT = FALSE;
GtkWidget *window;
@@ -87,8 +90,20 @@ extern GtkButton *gtk_start_again_button
gboolean greeter_probably_login_prompt = FALSE;
static gboolean first_prompt = TRUE;
+static void gui_process_form(void);
static void process_operation (guchar opcode, const gchar *args);
+static void entry_activate_handler (GtkWidget* widget, gpointer user_data);
+
+PamForm pam_form[256-'\n'] = {{0, NULL, NULL}};
+unsigned num_pam_form;
+
+#define FORM_SUPPORTED -1U
+unsigned form_serialize_idx = FORM_SUPPORTED;
+static GtkWidget* pam_form_vbox;
+static char* form_args; // strings in pam_form point in here
+static char* form_reply_str;
+
void
greeter_ignore_buttons (gboolean val)
{
@@ -135,6 +150,8 @@ greeter_ctrl_handler (GIOChannel *source
gchar *p;
gsize len;
+ dbg("");
+
/* If this is not incoming i/o then return */
if (cond != G_IO_IN)
return TRUE;
@@ -165,6 +182,222 @@ greeter_ctrl_handler (GIOChannel *source
}
static void
+form_serialize(void)
+{
+ unsigned i, needed_empty_replies = 0;
+ gboolean got_prompt = FALSE;
+
+ dbg("%d", form_serialize_idx);
+
+ if(form_serialize_idx >= num_pam_form) {
+ gdm_common_fail_greeter("serialize index out of range");
+ }
+
+ for(i = form_serialize_idx; !got_prompt && i < num_pam_form; ++i)
+ {
+ switch(pam_form[i].style)
+ {
+ case GDM_MSG:
+ greeter_item_pam_message (pam_form[i].msg);
+ ++needed_empty_replies;
+ break;
+ case GDM_ERRBOX:
+ greeter_item_pam_error (pam_form[i].msg);
+ ++needed_empty_replies;
+ break;
+ default:
+ got_prompt = TRUE;
+ process_operation(pam_form[i].style, pam_form[i].msg);
+ break;
+ }
+ }
+ form_serialize_idx = i;
+
+ if(needed_empty_replies)
+ {
+ if(form_reply_str)
+ form_reply_str = g_realloc(form_reply_str, strlen(form_reply_str)+1+needed_empty_replies);
+ else
+ form_reply_str = g_malloc0(needed_empty_replies+1);
+ memset(form_reply_str+strlen(form_reply_str), EOX, needed_empty_replies);
+ }
+
+ if(!got_prompt)
+ {
+ GreeterItemInfo *entry_info = greeter_lookup_id ("user-pw-entry");
+ if (entry_info && entry_info->item &&
+ GNOME_IS_CANVAS_WIDGET (entry_info->item) &&
+ GTK_IS_ENTRY (GNOME_CANVAS_WIDGET (entry_info->item)->widget))
+ {
+ entry_activate_handler(GNOME_CANVAS_WIDGET(entry_info->item)->widget, NULL);
+ }
+ }
+}
+
+static void
+gui_process_form(void)
+{
+ int i;
+ int firstentry = -1;
+ GtkWidget* preventry = NULL;
+ GtkWidget* form_frame;
+ GreeterItemInfo* item = greeter_lookup_id ("pam-form");
+
+ dbg("num_pam_form %d", num_pam_form);
+
+
+ if (item && item->item
+ && GNOME_IS_CANVAS_WIDGET (item->item)
+ && GTK_IS_FRAME (GNOME_CANVAS_WIDGET (item->item)->widget)) {
+ form_frame = GNOME_CANVAS_WIDGET (item->item)->widget;
+ }
+ else
+ {
+ return;
+ }
+
+ pam_form_vbox = gtk_bin_get_child(GTK_BIN(form_frame));
+
+ if(pam_form_vbox)
+ gtk_container_remove(GTK_CONTAINER(form_frame), pam_form_vbox);
+
+ pam_form_vbox = gtk_vbox_new(FALSE, 0);
+
+ for (i = 0; i < num_pam_form; ++i)
+ {
+ unsigned style = pam_form[i].style;
+ char* msg = ve_locale_to_utf8(pam_form[i].msg);
+
+ dbg("%c %s", style, msg);
+
+ switch(style)
+ {
+ case GDM_NOECHO:
+ case GDM_PROMPT:
+ {
+ GtkWidget* hbox;
+ GtkWidget* label;
+ GtkWidget* entry;
+ gboolean is_username;
+
+ if((is_username = !strcmp(msg, _("Username:"))))
+ msg = _("_Username:");
+
+ hbox = gtk_hbox_new(FALSE, 4);
+ label = gtk_label_new_with_mnemonic(msg);
+ pam_form[i].widget = entry = gtk_entry_new();
+ //gtk_widget_set_size_request (entry, 200, -1);
+
+ gtk_entry_set_max_length (GTK_ENTRY (entry), PW_ENTRY_SIZE);
+ gtk_entry_set_visibility(GTK_ENTRY(entry), (style == GDM_PROMPT));
+
+ gdm_common_setup_blinking_entry (entry);
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
+
+ gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, TRUE, 0);
+
+ gtk_box_pack_start(GTK_BOX(pam_form_vbox), hbox, TRUE, TRUE, 0);
+
+ if(firstentry == -1)
+ firstentry = i;
+
+ if(is_username)
+ {
+ msg = NULL; // static string from gettext, prevent g_free()
+
+#warning FIXME
+#if 0
+ if(selected_user)
+ gtk_entry_set_text (GTK_ENTRY(entry), selected_user);
+
+ g_signal_connect (G_OBJECT (entry), "focus_in_event",
+ G_CALLBACK (username_prompt_focus_in),
+ NULL);
+ g_signal_connect (G_OBJECT (entry), "focus_out_event",
+ G_CALLBACK (username_prompt_focus_out),
+ NULL);
+
+ g_signal_connect (G_OBJECT (entry), "key_press_event",
+ G_CALLBACK (gdm_evil_handler_pressed), NULL);
+#endif
+
+ gdm_common_login_sound (gdm_config_get_string (GDM_KEY_SOUND_PROGRAM),
+ gdm_config_get_string (GDM_KEY_SOUND_ON_LOGIN_FILE),
+ gdm_config_get_bool (GDM_KEY_SOUND_ON_LOGIN));
+ }
+
+ if(preventry)
+ {
+ g_signal_connect_swapped((gpointer)preventry, "activate",
+ G_CALLBACK(gtk_widget_grab_focus),
+ entry);
+ }
+
+ preventry = entry;
+
+ } break;
+ case GDM_MSG:
+ case GDM_ERRBOX:
+ {
+ GtkWidget* hbox;
+ GtkWidget* label;
+ GtkWidget* icon;
+
+ hbox = gtk_hbox_new(FALSE, 0);
+ label = gtk_label_new(msg);
+
+ gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+
+ if(style == GDM_ERRBOX)
+ icon = gtk_image_new_from_stock(
+ GTK_STOCK_DIALOG_ERROR,
+ GTK_ICON_SIZE_BUTTON);
+ else
+ icon = gtk_image_new_from_stock(
+ GTK_STOCK_DIALOG_INFO,
+ GTK_ICON_SIZE_BUTTON);
+
+ gtk_box_pack_start(GTK_BOX(hbox), icon, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+
+ gtk_box_pack_start(GTK_BOX(pam_form_vbox), hbox, TRUE, TRUE, 2);
+
+ } break;
+ }
+
+ g_free(msg);
+ }
+
+ gtk_widget_show_all(pam_form_vbox);
+
+ gtk_container_add(GTK_CONTAINER(form_frame), pam_form_vbox);
+
+ if(firstentry != -1)
+ {
+ gtk_widget_grab_focus(pam_form[firstentry].widget);
+ }
+ else
+ {
+ gtk_widget_grab_focus(GTK_WIDGET(gtk_ok_button));
+ }
+
+ // enter in last entry behaves like klicking the ok button
+ if(preventry)
+ {
+ g_signal_connect_swapped((gpointer)preventry, "activate",
+ G_CALLBACK (gtk_button_clicked),
+ gtk_ok_button);
+ }
+
+ if(gtk_start_again_button)
+ gtk_widget_set_sensitive (GTK_WIDGET(gtk_start_again_button), TRUE);
+ if(gtk_ok_button)
+ gtk_widget_set_sensitive (GTK_WIDGET(gtk_ok_button), TRUE);
+}
+
+static void
process_operation (guchar op_code,
const gchar *args)
{
@@ -180,6 +413,8 @@ process_operation (guchar op_code,
gchar *secondmsg = NULL;
gint save_session = GTK_RESPONSE_NO;
+ dbg("%c %s", op_code, args);
+
/* Parse opcode */
switch (op_code) {
case GDM_SETLOGIN:
@@ -191,6 +426,33 @@ process_operation (guchar op_code,
fflush (stdout);
break;
+ case GDM_PAM_FORM:
+ {
+ GreeterItemInfo* item = greeter_lookup_id ("pam-form");
+ if (item && item->item
+ && GNOME_IS_CANVAS_WIDGET (item->item)
+ && GTK_IS_FRAME (GNOME_CANVAS_WIDGET (item->item)->widget)) {
+ form_serialize_idx = FORM_SUPPORTED;
+ } else {
+ form_serialize_idx = 0;
+ g_free(form_reply_str);
+ form_reply_str = NULL;
+ g_free(form_args);
+ // make copy as we leave this function
+ form_args = g_strdup(args);
+ args = form_args;
+ }
+
+ if(parse_form(args))
+ {
+ if(form_serialize_idx == FORM_SUPPORTED)
+ gui_process_form();
+ else
+ form_serialize();
+ }
+ }
+ break;
+
case GDM_PROMPT:
tmp = ve_locale_to_utf8 (args);
if (tmp != NULL && strcmp (tmp, _("Username:")) == 0) {
@@ -540,6 +802,45 @@ key_press_event (GtkWidget *widget, GdkE
return FALSE;
}
+static void
+entry_activate_handler (GtkWidget *widget,
+ gpointer user_data)
+{
+ const char* str;
+ char* tmp;
+
+ g_return_if_fail(GTK_IS_ENTRY(widget));
+
+ if ((str = greeter_item_pam_login (GTK_ENTRY (widget))))
+ {
+ if(form_serialize_idx != FORM_SUPPORTED)
+ {
+ if(form_reply_str)
+ form_reply_str = g_realloc(form_reply_str, strlen(form_reply_str)+2+strlen(str));
+ else
+ form_reply_str = g_malloc0(strlen(str)+1);
+ tmp = ve_locale_from_utf8(str);
+ sprintf(form_reply_str+strlen(form_reply_str), "%s%c", tmp, EOX);
+ g_free(tmp);
+ }
+ }
+
+ dbg("%d %d %s", form_serialize_idx, num_pam_form, form_reply_str);
+
+ if(form_serialize_idx < num_pam_form)
+ {
+ form_serialize();
+ }
+ else
+ {
+ fputc(STX, stdout);
+ puts(form_reply_str);
+ fflush (stdout);
+ g_free(form_reply_str);
+ form_reply_str = NULL;
+ }
+}
+
/*
* The buttons with these handlers never appear in the F10 menu,
* so they can make use of callback data.
@@ -548,6 +849,7 @@ static void
greeter_ok_handler (GreeterItemInfo *info,
gpointer user_data)
{
+ const char* str;
if (ignore_buttons == FALSE)
{
GreeterItemInfo *entry_info = greeter_lookup_id ("user-pw-entry");
@@ -557,8 +859,7 @@ greeter_ok_handler (GreeterItemInfo *inf
{
GtkWidget *entry;
entry = GNOME_CANVAS_WIDGET (entry_info->item)->widget;
- greeter_ignore_buttons (TRUE);
- greeter_item_pam_login (GTK_ENTRY (entry), entry_info);
+ entry_activate_handler(entry, NULL);
}
}
}
@@ -580,6 +881,8 @@ greeter_cancel_handler (GreeterItemInfo
static void
greeter_setup_items (void)
{
+ GreeterItemInfo* entry_info;
+
greeter_item_clock_setup ();
greeter_item_pam_setup ();
@@ -588,6 +891,18 @@ greeter_setup_items (void)
greeter_item_capslock_setup (window);
greeter_item_timed_setup ();
+
+
+ entry_info = greeter_lookup_id ("user-pw-entry");
+ if (entry_info && entry_info->item &&
+ GNOME_IS_CANVAS_WIDGET (entry_info->item) &&
+ GTK_IS_ENTRY (GNOME_CANVAS_WIDGET (entry_info->item)->widget))
+ {
+ g_signal_connect((gpointer)GNOME_CANVAS_WIDGET (entry_info->item)->widget, "activate",
+ G_CALLBACK (entry_activate_handler),
+ NULL);
+ }
+
greeter_item_register_action_callback ("ok_button",
greeter_ok_handler,
(gpointer) window);
@@ -1126,6 +1441,7 @@ gdm_event (GSignalInvocationHint *ihint,
&& event->button.button == 3)
event->button.button = 1;
+#if 0
/* Support Ctrl-U for blanking the username/password entry */
if (event->type == GDK_KEY_PRESS &&
(event->key.state & GDK_CONTROL_MASK) &&
@@ -1142,6 +1458,7 @@ gdm_event (GSignalInvocationHint *ihint,
gtk_entry_set_text (GTK_ENTRY (entry), "");
}
}
+#endif
return TRUE;
}
@@ -1493,6 +1810,16 @@ main (int argc, char *argv[])
greeter_item_ulist_enable ();
greeter_item_ulist_check_show_userlist ();
+ if G_UNLIKELY (DOING_GDM_DEVELOPMENT) {
+ memset(pam_form, 0, sizeof(pam_form));
+ pam_form[0].style = GDM_PROMPT;
+ pam_form[0].msg = "Username:";
+ pam_form[1].style = GDM_NOECHO;
+ pam_form[1].msg = "Password:";
+ num_pam_form = 2;
+ gui_process_form();
+ }
+
/* can it ever happen that it'd be NULL here ??? */
if G_UNLIKELY (window->window != NULL)
{
Index: gdm2/gui/greeter/greeter_canvas_item.c
===================================================================
--- gdm2.orig/gui/greeter/greeter_canvas_item.c
+++ gdm2/gui/greeter/greeter_canvas_item.c
@@ -446,8 +446,9 @@ greeter_item_create_canvas_item (Greeter
break;
case GREETER_ITEM_TYPE_ENTRY:
+#if 1
entry = gtk_entry_new ();
- gtk_widget_set_name (entry, "user-pw-entry");
+ gtk_widget_set_name (entry, item->id);
gtk_entry_set_has_frame (GTK_ENTRY (entry), FALSE);
if (gdm_config_get_bool (GDM_KEY_ENTRY_INVISIBLE))
@@ -490,6 +491,15 @@ greeter_item_create_canvas_item (Greeter
/* FIXME: how to make this accessible??? */
}
+ /* cursor blinking is evil on remote displays, don't do it forever */
+ gdm_common_setup_blinking_entry (entry);
+#else
+ entry = gtk_frame_new("form frame");
+ gtk_widget_set_name (entry, item->id);
+ get_gdk_color_from_rgb (&c, item->data.text.colors[GREETER_ITEM_STATE_NORMAL]);
+ gtk_widget_modify_text (entry, GTK_STATE_NORMAL, &c);
+#endif
+
item->item = gnome_canvas_item_new (group,
GNOME_TYPE_CANVAS_WIDGET,
"widget", entry,
@@ -499,9 +509,6 @@ greeter_item_create_canvas_item (Greeter
"width", (double)rect.width,
NULL);
- /* cursor blinking is evil on remote displays, don't do it forever */
- gdm_common_setup_blinking_entry (entry);
-
break;
case GREETER_ITEM_TYPE_LIST:
Index: gdm2/gui/greeter/greeter_parser.c
===================================================================
--- gdm2.orig/gui/greeter/greeter_parser.c
+++ gdm2/gui/greeter/greeter_parser.c
@@ -430,11 +430,17 @@ parse_stock (xmlNodePtr node,
}
if (is_error)
+ {
+ g_free(*translated_text);
+ *translated_text = g_strdup("XXX");
+ is_error = FALSE;
+ }
+ if (is_error)
{
g_set_error (error,
GREETER_PARSER_ERROR,
GREETER_PARSER_ERROR_BAD_SPEC,
- "Bad stock label type");
+ "Bad stock label type %s", prop);
xmlFree (prop);
return FALSE;
}
Index: gdm2/gui/greeter/greeter_item_pam.c
===================================================================
--- gdm2.orig/gui/greeter/greeter_item_pam.c
+++ gdm2/gui/greeter/greeter_item_pam.c
@@ -37,6 +37,8 @@
#include "gdmwm.h"
#include "gdmcommon.h"
+#define dbg(fmt, args...) do { gdm_common_info("%s:%d %s() - " fmt, __FILE__, __LINE__, __FUNCTION__, ##args); } while(0)
+
static gboolean messages_to_give = FALSE;
static gboolean replace_msg = TRUE;
static guint err_box_clear_handler = 0;
@@ -117,8 +119,8 @@ set_text (GreeterItemInfo *info, const c
info->item);
}
-void
-greeter_item_pam_login (GtkEntry *entry, GreeterItemInfo *info)
+const char*
+greeter_item_pam_login (GtkEntry *entry)
{
const char *str;
char *tmp;
@@ -132,6 +134,7 @@ greeter_item_pam_login (GtkEntry *entry,
greeter_ignore_buttons (TRUE);
str = gtk_entry_get_text (GTK_ENTRY (entry));
+ dbg("%s", str);
if (greeter_probably_login_prompt &&
/* evilness */
evil (entry, str))
@@ -139,19 +142,9 @@ greeter_item_pam_login (GtkEntry *entry,
/* obviously being 100% reliable is not an issue for
this test */
gtk_entry_set_text (GTK_ENTRY (entry), "");
- return;
+ return NULL;
}
- if (greeter_probably_login_prompt &&
- ve_string_empty (str) &&
- greeter_item_timed_is_timed ())
- {
- /* timed interruption */
- printf ("%c%c%c\n", STX, BEL, GDM_INTERRUPT_TIMED_LOGIN);
- fflush (stdout);
- return;
- }
-
gtk_widget_set_sensitive (GTK_WIDGET (entry), FALSE);
/* clear the err_box */
@@ -165,11 +158,9 @@ greeter_item_pam_login (GtkEntry *entry,
greeter_item_pam_error_set (FALSE);
set_text (error_info, "");
}
-
- tmp = ve_locale_from_utf8 (str);
- printf ("%c%s\n", STX, tmp);
- fflush (stdout);
- g_free (tmp);
+ dbg("%s", str);
+
+ return str;
}
static gboolean
@@ -184,6 +175,7 @@ pam_key_release_event (GtkWidget *entry,
const char *login_string;
GtkWidget *entry = GNOME_CANVAS_WIDGET (entry_info->item)->widget;
+#if 0
if ((event->keyval == GDK_Tab ||
event->keyval == GDK_KP_Tab) &&
(event->state & (GDK_CONTROL_MASK|GDK_MOD1_MASK|GDK_SHIFT_MASK)) == 0)
@@ -191,6 +183,7 @@ pam_key_release_event (GtkWidget *entry,
greeter_item_pam_login (GTK_ENTRY (entry), entry_info);
return TRUE;
}
+#endif
if (gtk_ok_button != NULL)
{
@@ -235,8 +228,10 @@ greeter_item_pam_setup (void)
gtk_widget_set_sensitive (entry, FALSE);
}
+#if 0
g_signal_connect (entry, "activate",
G_CALLBACK (greeter_item_pam_login), entry_info);
+#endif
g_signal_connect (G_OBJECT (entry), "key_release_event",
G_CALLBACK (pam_key_release_event), NULL);
}
Index: gdm2/gui/greeter/greeter_item_pam.h
===================================================================
--- gdm2.orig/gui/greeter/greeter_item_pam.h
+++ gdm2/gui/greeter/greeter_item_pam.h
@@ -29,7 +29,7 @@ void greeter_item_pam_message (const cha
void greeter_item_pam_error (const char *message);
void greeter_item_pam_set_user (const char *user);
void greeter_item_pam_leftover_messages (void);
-void greeter_item_pam_login (GtkEntry *entry, GreeterItemInfo *info);
+const char* greeter_item_pam_login (GtkEntry *entry);
extern gchar *greeter_current_user;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]