~lightdm-team/lightdm/1.4

« back to all changes in this revision

Viewing changes to src/display.c

  • Committer: robert.ancell at canonical
  • Date: 2011-02-20 10:27:53 UTC
  • Revision ID: robert.ancell@canonical.com-20110220102753-2kehwju1amzcpoag
Use a private pipe for greeter<->server communication instead of D-Bus (needs to be fixed in liblightdm-qt)

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
#include <gio/gdesktopappinfo.h>
19
19
 
20
20
#include "display.h"
21
 
#include "display-glue.h"
22
21
#include "pam-session.h"
23
22
#include "theme.h"
24
23
#include "ldm-marshal.h"
25
24
#include "ck-connector.h"
 
25
#include "greeter-protocol.h"
26
26
 
27
27
/* Length of time in milliseconds to wait for a session to load */
28
28
#define USER_SESSION_TIMEOUT 5000
36
36
    START_SESSION,
37
37
    END_SESSION,
38
38
    EXITED,
39
 
    QUIT_GREETER,
40
39
    LAST_SIGNAL
41
40
};
42
41
static guint signals[LAST_SIGNAL] = { 0 };
75
74
    /* PAM service to authenticate against */
76
75
    gchar *pam_service;
77
76
 
 
77
    /* Pipe to communicate to greeter */
 
78
    int greeter_pipe[2];
 
79
 
78
80
    /* Greeter session process */
79
81
    Session *greeter_session;
80
82
    gboolean greeter_connected;
90
92
    PAMSession *user_pam_session;
91
93
    CkConnector *user_ck_session;
92
94
 
93
 
    /* Current D-Bus call context */
94
 
    DBusGMethodInvocation *dbus_context;
95
 
 
96
95
    /* Default login hint */
97
96
    gchar *default_user;
98
97
    gint timeout;
507
506
 
508
507
            g_signal_emit (display, signals[START_SESSION], 0, display->priv->user_session);
509
508
 
510
 
            session_start (display->priv->user_session);
 
509
            session_start (display->priv->user_session, FALSE);
511
510
 
512
511
            data = g_key_file_to_data (dmrc_file, &length, NULL);
513
512
 
591
590
}
592
591
 
593
592
static void
594
 
greeter_session_exited_cb (Session *session, gint status, Display *display)
595
 
{
596
 
    end_greeter_session (display, status == 0);
597
 
}
598
 
 
599
 
static void
600
 
greeter_session_killed_cb (Session *session, gint status, Display *display)
601
 
{
602
 
    end_greeter_session (display, FALSE);
603
 
}
604
 
 
605
 
static void
606
 
start_greeter (Display *display)
607
 
{
608
 
    GKeyFile *theme;
609
 
    GError *error = NULL;
610
 
  
611
 
    theme = load_theme (display->priv->greeter_theme, &error);
612
 
    if (!theme)
613
 
        g_warning ("Failed to find theme %s: %s", display->priv->greeter_theme, error->message);
614
 
    g_clear_error (&error);
615
 
 
616
 
    if (theme)
 
593
handle_connect (Display *display)
 
594
{
 
595
    gchar *theme;
 
596
 
 
597
    if (!display->priv->greeter_connected)
617
598
    {
618
 
        gchar *command;
619
 
        gchar *username = NULL;
620
 
 
621
 
        g_debug ("Starting greeter %s as user %s", display->priv->greeter_theme,
622
 
                 display->priv->greeter_user ? display->priv->greeter_user : "<current>");
623
 
 
624
 
        command = theme_get_command (theme);
625
 
      
626
 
        if (display->priv->greeter_user)
627
 
            username = display->priv->greeter_user;
628
 
        else
629
 
        {
630
 
            struct passwd *user_info;
631
 
            user_info = getpwuid (getuid ());
632
 
            if (!user_info)
633
 
            {
634
 
                g_warning ("Unable to determine current username: %s", strerror (errno));
635
 
                return;
636
 
            }
637
 
            username = user_info->pw_name;
638
 
        }
639
 
 
640
 
        display->priv->greeter_pam_session = pam_session_new (display->priv->pam_service, username);
641
 
        pam_session_authorize (display->priv->greeter_pam_session);
642
 
 
643
 
        display->priv->greeter_ck_session = start_ck_session (display,
644
 
                                                              "LoginWindow",
645
 
                                                              username);
646
 
 
647
 
        display->priv->greeter_connected = FALSE;
648
 
        display->priv->greeter_session = session_new (username, command);
649
 
        g_signal_connect (G_OBJECT (display->priv->greeter_session), "exited", G_CALLBACK (greeter_session_exited_cb), display);
650
 
        g_signal_connect (G_OBJECT (display->priv->greeter_session), "killed", G_CALLBACK (greeter_session_killed_cb), display);
651
 
        child_process_set_env (CHILD_PROCESS (display->priv->greeter_session), "DISPLAY", xserver_get_address (display->priv->xserver));
652
 
        if (display->priv->greeter_ck_session)
653
 
            child_process_set_env (CHILD_PROCESS (display->priv->greeter_session), "XDG_SESSION_COOKIE", ck_connector_get_cookie (display->priv->greeter_ck_session));
654
 
        set_env_from_pam_session (display->priv->greeter_session, display->priv->greeter_pam_session);
655
 
 
656
 
        g_signal_emit (display, signals[START_GREETER], 0, display->priv->greeter_session);
657
 
 
658
 
        session_start (display->priv->greeter_session);
659
 
 
660
 
        g_free (command);
661
 
        g_key_file_free (theme);
 
599
        display->priv->greeter_connected = TRUE;
 
600
        g_debug ("Greeter connected");
662
601
    }
 
602
 
 
603
    child_process_write_int (CHILD_PROCESS (display->priv->greeter_session), GREETER_MESSAGE_CONNECTED);
 
604
    theme = g_build_filename (THEME_DIR, display->priv->greeter_theme, "index.theme", NULL);
 
605
    child_process_write_string (CHILD_PROCESS (display->priv->greeter_session), theme);
 
606
    g_free (theme);
 
607
    child_process_write_string (CHILD_PROCESS (display->priv->greeter_session), display->priv->default_layout);
 
608
    child_process_write_string (CHILD_PROCESS (display->priv->greeter_session), display->priv->default_session);
 
609
    child_process_write_string (CHILD_PROCESS (display->priv->greeter_session), display->priv->default_user ? display->priv->default_user : "");
 
610
    child_process_write_int (CHILD_PROCESS (display->priv->greeter_session), display->priv->timeout);
 
611
    child_process_flush (CHILD_PROCESS (display->priv->greeter_session));
663
612
}
664
613
 
665
 
#define TYPE_MESSAGE dbus_g_type_get_struct ("GValueArray", G_TYPE_INT, G_TYPE_STRING, G_TYPE_INVALID)
666
 
 
667
614
static void
668
615
pam_messages_cb (PAMSession *session, int num_msg, const struct pam_message **msg, Display *display)
669
616
{
670
 
    GPtrArray *request;
671
617
    int i;
672
 
    DBusGMethodInvocation *context;
673
618
 
674
619
    /* Respond to d-bus query with messages */
675
 
    request = g_ptr_array_new ();
 
620
    g_debug ("Prompt greeter with %d message(s)", num_msg);
 
621
    child_process_write_int (CHILD_PROCESS (display->priv->greeter_session), GREETER_MESSAGE_PROMPT_AUTHENTICATION);
 
622
    child_process_write_int (CHILD_PROCESS (display->priv->greeter_session), num_msg);
676
623
    for (i = 0; i < num_msg; i++)
677
624
    {
678
 
        GValue value = { 0 };
679
 
      
680
 
        g_value_init (&value, TYPE_MESSAGE);
681
 
        g_value_take_boxed (&value, dbus_g_type_specialized_construct (TYPE_MESSAGE));
682
 
        // FIXME: Need to convert to UTF-8
683
 
        dbus_g_type_struct_set (&value, 0, msg[i]->msg_style, 1, msg[i]->msg, G_MAXUINT);
684
 
        g_ptr_array_add (request, g_value_get_boxed (&value));
 
625
        child_process_write_int (CHILD_PROCESS (display->priv->greeter_session), msg[i]->msg_style);
 
626
        child_process_write_string (CHILD_PROCESS (display->priv->greeter_session), msg[i]->msg);
685
627
    }
686
 
 
687
 
    context = display->priv->dbus_context;
688
 
    display->priv->dbus_context = NULL;
689
 
    dbus_g_method_return (context, 0, request);
 
628
    child_process_flush (CHILD_PROCESS (display->priv->greeter_session));  
690
629
}
691
630
 
692
631
static void
693
632
authenticate_result_cb (PAMSession *session, int result, Display *display)
694
633
{
695
 
    GPtrArray *request;
696
 
    DBusGMethodInvocation *context;
697
 
 
698
634
    g_debug ("Authenticate result for user %s: %s", pam_session_get_username (display->priv->user_pam_session), pam_session_strerror (display->priv->user_pam_session, result));
699
635
 
700
636
    if (result == PAM_SUCCESS)
704
640
    }
705
641
 
706
642
    /* Respond to D-Bus request */
707
 
    request = g_ptr_array_new ();
708
 
    context = display->priv->dbus_context;
709
 
    display->priv->dbus_context = NULL;
710
 
 
711
 
    dbus_g_method_return (context, result, request);
 
643
    child_process_write_int (CHILD_PROCESS (display->priv->greeter_session), GREETER_MESSAGE_END_AUTHENTICATION);
 
644
    child_process_write_int (CHILD_PROCESS (display->priv->greeter_session), result);   
 
645
    child_process_flush (CHILD_PROCESS (display->priv->greeter_session));
712
646
}
713
647
 
714
648
static void
717
651
    display->priv->user_ck_session = start_ck_session (display, "", pam_session_get_username (display->priv->user_pam_session));
718
652
}
719
653
 
720
 
gboolean
721
 
display_connect (Display *display,
722
 
                 const gchar **theme,
723
 
                 const gchar **layout, const gchar **session,
724
 
                 const gchar **username, gint *delay, GError *error)
725
 
{
726
 
    if (!display->priv->greeter_connected)
727
 
    {
728
 
        display->priv->greeter_connected = TRUE;
729
 
        g_debug ("Greeter connected");
730
 
    }
731
 
 
732
 
    *theme = g_build_filename (THEME_DIR, display->priv->greeter_theme, "index.theme", NULL);
733
 
    *layout = g_strdup (display->priv->default_layout);
734
 
    *session = g_strdup (display->priv->default_session);
735
 
    *username = g_strdup (display->priv->default_user);
736
 
    *delay = display->priv->timeout;
737
 
 
738
 
    return TRUE;
739
 
}
740
 
 
741
 
gboolean
742
 
display_start_authentication (Display *display, const gchar *username, DBusGMethodInvocation *context)
 
654
static void
 
655
handle_start_authentication (Display *display, const gchar *username)
743
656
{
744
657
    GError *error = NULL;
745
658
 
746
 
    // FIXME: Only allow calls from the correct greeter
747
 
 
748
659
    if (!display->priv->greeter_session || display->priv->user_session)
749
 
    {
750
 
        dbus_g_method_return_error (context, NULL);
751
 
        return TRUE;
752
 
    }
 
660
        return;
753
661
 
754
662
    /* Abort existing authentication */
755
663
    if (display->priv->user_pam_session)
756
664
    {
757
665
        g_signal_handlers_disconnect_matched (display->priv->user_pam_session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
758
666
        pam_session_end (display->priv->user_pam_session);
759
 
        if (display->priv->dbus_context)
760
 
            dbus_g_method_return_error (display->priv->dbus_context, NULL);
761
 
 
762
667
        g_object_unref (display->priv->user_pam_session);
763
668
    }
764
669
 
765
670
    g_debug ("Greeter start authentication for %s", username);
766
671
 
767
 
    /* Store D-Bus request to respond to */
768
 
    display->priv->dbus_context = context;
769
 
 
770
672
    display->priv->user_pam_session = pam_session_new (display->priv->pam_service, username);
771
673
    g_signal_connect (G_OBJECT (display->priv->user_pam_session), "got-messages", G_CALLBACK (pam_messages_cb), display);
772
674
    g_signal_connect (G_OBJECT (display->priv->user_pam_session), "authentication-result", G_CALLBACK (authenticate_result_cb), display);
773
675
    g_signal_connect (G_OBJECT (display->priv->user_pam_session), "started", G_CALLBACK (session_started_cb), display);
774
676
 
775
677
    if (!pam_session_start (display->priv->user_pam_session, &error))
776
 
    {
777
678
        g_warning ("Failed to start authentication: %s", error->message);
778
 
        display->priv->dbus_context = NULL;
779
 
        dbus_g_method_return_error (context, NULL);
780
 
        return FALSE;
781
 
    }
782
 
    g_clear_error (&error);
783
 
 
784
 
    return TRUE;
785
679
}
786
680
 
787
 
gboolean
788
 
display_continue_authentication (Display *display, gchar **secrets, DBusGMethodInvocation *context)
 
681
static void
 
682
handle_continue_authentication (Display *display, gchar **secrets)
789
683
{
790
684
    int num_messages;
791
685
    const struct pam_message **messages;
794
688
 
795
689
    /* Not connected */
796
690
    if (!display->priv->greeter_connected)
797
 
    {
798
 
        dbus_g_method_return_error (context, NULL);
799
 
        return TRUE;
800
 
    }
 
691
        return;
801
692
 
802
693
    /* Not in authorization */
803
694
    if (display->priv->user_pam_session == NULL)
804
 
    {
805
 
        dbus_g_method_return_error (context, NULL);
806
 
        return TRUE;
807
 
    }
808
 
 
809
 
    /* Already in another call */
810
 
    if (display->priv->dbus_context != NULL)
811
 
    {
812
 
        dbus_g_method_return_error (context, NULL);
813
 
        return TRUE;
814
 
    }
 
695
        return;
815
696
 
816
697
    // FIXME: Only allow calls from the correct greeter
817
698
 
828
709
    if (g_strv_length (secrets) != n_secrets)
829
710
    {
830
711
        pam_session_end (display->priv->user_pam_session);
831
 
        // FIXME: Throw error
832
 
        return FALSE;
 
712
        return;
833
713
    }
834
714
 
835
715
    g_debug ("Continue authentication");
846
726
        }
847
727
    }
848
728
 
849
 
    display->priv->dbus_context = context;
850
729
    pam_session_respond (display->priv->user_pam_session, response);
851
 
 
852
 
    return TRUE;
853
730
}
854
731
 
855
732
static gboolean
865
742
static void
866
743
quit_greeter (Display *display)
867
744
{
868
 
    g_signal_emit (display, signals[QUIT_GREETER], 0);
 
745
    child_process_write_int (CHILD_PROCESS (display->priv->greeter_session), GREETER_MESSAGE_QUIT);
 
746
    child_process_flush (CHILD_PROCESS (display->priv->greeter_session));
 
747
 
869
748
    if (display->priv->greeter_quit_timeout)
870
749
        g_source_remove (display->priv->greeter_quit_timeout);
871
750
    display->priv->greeter_quit_timeout = g_timeout_add (GREETER_QUIT_TIMEOUT, quit_greeter_cb, display);
883
762
    return FALSE;
884
763
}
885
764
 
886
 
gboolean
887
 
display_login (Display *display, gchar *username, gchar *session, gchar *language, GError *error)
 
765
static void
 
766
handle_login (Display *display, gchar *username, gchar *session, gchar *language)
888
767
{
889
768
    if (display->priv->user_session != NULL)
890
769
    {
891
770
        g_warning ("Ignoring request to log in when already logged in");
892
 
        return TRUE;
 
771
        return;
893
772
    }
894
773
 
895
774
    g_debug ("Greeter login for user %s on session %s", username, session);
911
790
    else
912
791
    {
913
792
        g_warning ("Ignoring request for login with unauthenticated user");
914
 
        return FALSE;
 
793
        return;
915
794
    }
916
795
 
917
796
    /* Stop session, waiting for user session to indicate it is ready (if supported) */
920
799
        display->priv->user_session_timer = g_timeout_add (USER_SESSION_TIMEOUT, (GSourceFunc) session_timeout_cb, display);
921
800
    else
922
801
        quit_greeter (display);
923
 
 
924
 
    return TRUE;
 
802
}
 
803
 
 
804
static void
 
805
greeter_data_cb (Session *session, Display *display)
 
806
{
 
807
    int message, n_secrets, i;
 
808
    gchar *username, *session_name, *language;
 
809
    gchar **secrets;
 
810
 
 
811
    /* FIXME: This could all block and lock up the server */
 
812
 
 
813
    message = child_process_read_int (CHILD_PROCESS (session));
 
814
    switch (message)
 
815
    {
 
816
    case GREETER_MESSAGE_CONNECT:
 
817
        handle_connect (display);
 
818
        break;
 
819
    case GREETER_MESSAGE_START_AUTHENTICATION:
 
820
        username = child_process_read_string (CHILD_PROCESS (session));
 
821
        handle_start_authentication (display, username);
 
822
        g_free (username);
 
823
        break;
 
824
    case GREETER_MESSAGE_CONTINUE_AUTHENTICATION:
 
825
        n_secrets = child_process_read_int (CHILD_PROCESS (session));
 
826
        secrets = g_malloc (sizeof (gchar *) * (n_secrets + 1));
 
827
        for (i = 0; i < n_secrets; i++)
 
828
            secrets[i] = child_process_read_string (CHILD_PROCESS (session));
 
829
        secrets[i] = NULL;
 
830
        handle_continue_authentication (display, secrets);
 
831
        g_strfreev (secrets);
 
832
        break;
 
833
    case GREETER_MESSAGE_LOGIN:
 
834
        username = child_process_read_string (CHILD_PROCESS (session));
 
835
        session_name = child_process_read_string (CHILD_PROCESS (session));
 
836
        language = child_process_read_string (CHILD_PROCESS (session));
 
837
        handle_login (display, username, session_name, language);
 
838
        g_free (username);
 
839
        g_free (session_name);
 
840
        g_free (language);
 
841
        break;
 
842
    default:
 
843
        g_warning ("Unknown message from greeter: %d", message);
 
844
        break;
 
845
    }
 
846
}
 
847
 
 
848
static void
 
849
greeter_session_exited_cb (Session *session, gint status, Display *display)
 
850
{
 
851
    end_greeter_session (display, status == 0);
 
852
}
 
853
 
 
854
static void
 
855
greeter_session_killed_cb (Session *session, gint status, Display *display)
 
856
{
 
857
    end_greeter_session (display, FALSE);
 
858
}
 
859
 
 
860
static void
 
861
start_greeter (Display *display)
 
862
{
 
863
    GKeyFile *theme;
 
864
    GError *error = NULL;
 
865
  
 
866
    theme = load_theme (display->priv->greeter_theme, &error);
 
867
    if (!theme)
 
868
        g_warning ("Failed to find theme %s: %s", display->priv->greeter_theme, error->message);
 
869
    g_clear_error (&error);
 
870
 
 
871
    if (theme)
 
872
    {
 
873
        gchar *command;
 
874
        gchar *username = NULL;
 
875
 
 
876
        g_debug ("Starting greeter %s as user %s", display->priv->greeter_theme,
 
877
                 display->priv->greeter_user ? display->priv->greeter_user : "<current>");
 
878
 
 
879
        command = theme_get_command (theme);
 
880
      
 
881
        if (display->priv->greeter_user)
 
882
            username = display->priv->greeter_user;
 
883
        else
 
884
        {
 
885
            struct passwd *user_info;
 
886
            user_info = getpwuid (getuid ());
 
887
            if (!user_info)
 
888
            {
 
889
                g_warning ("Unable to determine current username: %s", strerror (errno));
 
890
                return;
 
891
            }
 
892
            username = user_info->pw_name;
 
893
        }
 
894
 
 
895
        display->priv->greeter_pam_session = pam_session_new (display->priv->pam_service, username);
 
896
        pam_session_authorize (display->priv->greeter_pam_session);
 
897
 
 
898
        display->priv->greeter_ck_session = start_ck_session (display,
 
899
                                                              "LoginWindow",
 
900
                                                              username);
 
901
 
 
902
        display->priv->greeter_connected = FALSE;
 
903
        display->priv->greeter_session = session_new (username, command);
 
904
        g_signal_connect (G_OBJECT (display->priv->greeter_session), "got-data", G_CALLBACK (greeter_data_cb), display);      
 
905
        g_signal_connect (G_OBJECT (display->priv->greeter_session), "exited", G_CALLBACK (greeter_session_exited_cb), display);
 
906
        g_signal_connect (G_OBJECT (display->priv->greeter_session), "killed", G_CALLBACK (greeter_session_killed_cb), display);
 
907
        child_process_set_env (CHILD_PROCESS (display->priv->greeter_session), "DISPLAY", xserver_get_address (display->priv->xserver));
 
908
        if (display->priv->greeter_ck_session)
 
909
            child_process_set_env (CHILD_PROCESS (display->priv->greeter_session), "XDG_SESSION_COOKIE", ck_connector_get_cookie (display->priv->greeter_ck_session));
 
910
        set_env_from_pam_session (display->priv->greeter_session, display->priv->greeter_pam_session);
 
911
 
 
912
        g_signal_emit (display, signals[START_GREETER], 0, display->priv->greeter_session);
 
913
 
 
914
        session_start (display->priv->greeter_session, TRUE);
 
915
 
 
916
        g_free (command);
 
917
        g_key_file_free (theme);
 
918
    }
925
919
}
926
920
 
927
921
static void
1047
1041
                      NULL, NULL,
1048
1042
                      g_cclosure_marshal_VOID__VOID,
1049
1043
                      G_TYPE_NONE, 0);
1050
 
 
1051
 
    signals[QUIT_GREETER] =
1052
 
        g_signal_new ("quit_greeter",
1053
 
                      G_TYPE_FROM_CLASS (klass),
1054
 
                      G_SIGNAL_RUN_LAST,
1055
 
                      G_STRUCT_OFFSET (DisplayClass, quit_greeter),
1056
 
                      NULL, NULL,
1057
 
                      g_cclosure_marshal_VOID__VOID,
1058
 
                      G_TYPE_NONE, 0);
1059
 
 
1060
 
    dbus_g_object_type_install_info (DISPLAY_TYPE, &dbus_glib_display_object_info);
1061
1044
}