]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - src/session.c
move where we insert our own utility PATH
[sojka/lightdm.git] / src / session.c
1 /*
2  * Copyright (C) 2010-2011 Robert Ancell.
3  * Author: Robert Ancell <robert.ancell@canonical.com>
4  * 
5  * This program is free software: you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License as published by the Free Software
7  * Foundation, either version 3 of the License, or (at your option) any later
8  * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
9  * license.
10  */
11
12 #include <stdlib.h>
13 #include <string.h>
14 #include <errno.h>
15 #include <unistd.h>
16 #include <sys/wait.h>
17 #include <fcntl.h>
18 #include <glib/gstdio.h>
19 #include <grp.h>
20
21 #include "session.h"
22 #include "configuration.h"
23
24 struct SessionPrivate
25 {
26     /* Authentication for this session */
27     PAMSession *authentication;
28   
29     /* Command to run for this session */
30     gchar *command;
31
32     /* Cookie for the session */
33     gchar *cookie;
34
35     /* TRUE if this is a greeter session */
36     gboolean is_greeter;
37 };
38
39 G_DEFINE_TYPE (Session, session, PROCESS_TYPE);
40
41 void
42 session_set_authentication (Session *session, PAMSession *authentication)
43 {
44     g_return_if_fail (session != NULL);
45     session->priv->authentication = g_object_ref (authentication);
46 }
47
48 PAMSession *
49 session_get_authentication (Session *session)
50 {
51     g_return_val_if_fail (session != NULL, NULL);
52     return session->priv->authentication;
53 }
54
55 User *
56 session_get_user (Session *session)
57 {
58     g_return_val_if_fail (session != NULL, NULL);
59     return pam_session_get_user (session->priv->authentication);
60 }
61
62 void
63 session_set_is_greeter (Session *session, gboolean is_greeter)
64 {
65     g_return_if_fail (session != NULL);
66     session->priv->is_greeter = is_greeter;
67 }
68
69 gboolean
70 session_get_is_greeter (Session *session)
71 {
72     g_return_val_if_fail (session != NULL, FALSE);
73     return session->priv->is_greeter;
74 }
75
76 void
77 session_set_command (Session *session, const gchar *command)
78 {
79     g_return_if_fail (session != NULL);
80
81     g_free (session->priv->command);
82     session->priv->command = g_strdup (command);
83 }
84
85 const gchar *
86 session_get_command (Session *session)
87 {
88     g_return_val_if_fail (session != NULL, NULL);  
89     return session->priv->command;
90 }
91
92 void
93 session_set_cookie (Session *session, const gchar *cookie)
94 {
95     g_return_if_fail (session != NULL);
96
97     g_free (session->priv->cookie);
98     session->priv->cookie = g_strdup (cookie);
99 }
100
101 const gchar *
102 session_get_cookie (Session *session)
103 {
104     g_return_val_if_fail (session != NULL, NULL);  
105     return session->priv->cookie;
106 }
107
108 static gchar *
109 get_absolute_command (const gchar *command)
110 {
111     gchar **tokens;
112     gchar *absolute_binary, *absolute_command = NULL;
113
114     tokens = g_strsplit (command, " ", 2);
115
116     absolute_binary = g_find_program_in_path (tokens[0]);
117     if (absolute_binary)
118     {
119         if (tokens[1])
120             absolute_command = g_strjoin (" ", absolute_binary, tokens[1], NULL);
121         else
122             absolute_command = g_strdup (absolute_binary);
123     }
124
125     g_strfreev (tokens);
126
127     return absolute_command;
128 }
129
130 static void
131 set_env_from_authentication (Session *session, PAMSession *authentication)
132 {
133     gchar **pam_env;
134
135     pam_env = pam_session_get_envlist (authentication);
136     if (pam_env)
137     {
138         gchar *env_string;      
139         int i;
140
141         env_string = g_strjoinv (" ", pam_env);
142         g_debug ("PAM returns environment '%s'", env_string);
143         g_free (env_string);
144
145         for (i = 0; pam_env[i]; i++)
146         {
147             gchar **pam_env_vars = g_strsplit (pam_env[i], "=", 2);
148             if (pam_env_vars && pam_env_vars[0] && pam_env_vars[1])
149                 process_set_env (PROCESS (session), pam_env_vars[0], pam_env_vars[1]);
150             else
151                 g_warning ("Can't parse PAM environment variable %s", pam_env[i]);
152             g_strfreev (pam_env_vars);
153         }
154         g_strfreev (pam_env);
155     }
156 }
157
158 static gboolean
159 session_real_start (Session *session)
160 {
161     //gint session_stdin, session_stdout, session_stderr;
162     gboolean result;
163     User *user;
164     gchar *absolute_command;
165     const gchar *orig_path;
166     GError *error = NULL;
167
168     g_return_val_if_fail (session->priv->authentication != NULL, FALSE);
169     g_return_val_if_fail (session->priv->command != NULL, FALSE);
170
171     absolute_command = get_absolute_command (session->priv->command);
172     if (!absolute_command)
173     {
174         g_debug ("Can't launch session %s, not found in path", session->priv->command);
175         return FALSE;
176     }
177
178     pam_session_open (session->priv->authentication);
179
180     g_debug ("Launching session");
181
182     user = pam_session_get_user (session->priv->authentication);
183     process_set_env (PROCESS (session), "PATH", "/usr/local/bin:/usr/bin:/bin");
184     process_set_env (PROCESS (session), "USER", user_get_name (user));
185     process_set_env (PROCESS (session), "USERNAME", user_get_name (user)); // FIXME: Is this required?
186     process_set_env (PROCESS (session), "HOME", user_get_home_directory (user));
187     process_set_env (PROCESS (session), "SHELL", user_get_shell (user));
188     set_env_from_authentication (session, session->priv->authentication);
189
190     /* Insert our own utility directory to PATH
191      * This is to provide gdmflexiserver which provides backwards compatibility with GDM.
192      * Must be done after set_env_from_authentication because that often sets PATH.
193      * This can be removed when this is no longer required.
194      */
195     orig_path = process_get_env (PROCESS (session), "PATH");
196     if (orig_path)
197     {
198         gchar *path = g_strdup_printf ("%s:%s", PKGLIBEXEC_DIR, orig_path);
199         process_set_env (PROCESS (session), "PATH", path);
200         g_free (path);
201     }
202
203     if (session->priv->cookie)
204         process_set_env (PROCESS (session), "XDG_SESSION_COOKIE", session->priv->cookie);
205
206     result = process_start (PROCESS (session),
207                             user,
208                             user_get_home_directory (user),
209                             absolute_command,
210                             &error);
211     g_free (absolute_command);
212
213     if (!result)
214         g_warning ("Failed to spawn session: %s", error->message);
215     g_clear_error (&error);
216
217     return result;
218 }
219
220 gboolean
221 session_start (Session *session)
222 {
223     g_return_val_if_fail (session != NULL, FALSE); 
224     return SESSION_GET_CLASS (session)->start (session);
225 }
226
227 static void
228 session_real_stop (Session *session)
229 {
230     process_signal (PROCESS (session), SIGTERM);
231 }
232
233 void
234 session_stop (Session *session)
235 {
236     g_return_if_fail (session != NULL);
237     SESSION_GET_CLASS (session)->stop (session);
238 }
239
240 static void
241 session_stopped (Process *process)
242 {
243     Session *session = SESSION (process);
244
245     pam_session_close (session->priv->authentication);
246
247     PROCESS_CLASS (session_parent_class)->stopped (process);
248 }
249
250 static void
251 session_init (Session *session)
252 {
253     session->priv = G_TYPE_INSTANCE_GET_PRIVATE (session, SESSION_TYPE, SessionPrivate);
254 }
255
256 static void
257 session_finalize (GObject *object)
258 {
259     Session *self;
260
261     self = SESSION (object);
262
263     if (self->priv->authentication)
264         g_object_unref (self->priv->authentication);
265     g_free (self->priv->command);
266     g_free (self->priv->cookie);
267
268     G_OBJECT_CLASS (session_parent_class)->finalize (object);
269 }
270
271 static void
272 session_class_init (SessionClass *klass)
273 {
274     GObjectClass *object_class = G_OBJECT_CLASS (klass);
275     ProcessClass *process_class = PROCESS_CLASS (klass);
276
277     klass->start = session_real_start;
278     klass->stop = session_real_stop;
279     process_class->stopped = session_stopped;
280     object_class->finalize = session_finalize;
281
282     g_type_class_add_private (klass, sizeof (SessionPrivate));
283 }