~ubuntu-branches/ubuntu/lucid/openssh/lucid

30 by Colin Watson
Add support for registering ConsoleKit sessions on login.
1
/*
2
 * Copyright (c) 2008 Colin Watson.  All rights reserved.
3
 *
4
 * Permission to use, copy, modify, and distribute this software for any
5
 * purpose with or without fee is hereby granted, provided that the above
6
 * copyright notice and this permission notice appear in all copies.
7
 *
8
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
 */
16
/*
17
 * Loosely based on pam-ck-connector, which is:
18
 *
19
 * Copyright (c) 2007 David Zeuthen <davidz@redhat.com>
20
 *
21
 * Permission is hereby granted, free of charge, to any person
22
 * obtaining a copy of this software and associated documentation
23
 * files (the "Software"), to deal in the Software without
24
 * restriction, including without limitation the rights to use,
25
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
26
 * copies of the Software, and to permit persons to whom the
27
 * Software is furnished to do so, subject to the following
28
 * conditions:
29
 *
30
 * The above copyright notice and this permission notice shall be
31
 * included in all copies or substantial portions of the Software.
32
 *
33
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
34
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
35
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
36
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
37
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
38
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
39
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
40
 * OTHER DEALINGS IN THE SOFTWARE.
41
 */
42
43
#include "includes.h"
44
45
#ifdef USE_CONSOLEKIT
46
47
#include <ck-connector.h>
48
49
#include "xmalloc.h"
50
#include "channels.h"
51
#include "key.h"
52
#include "hostfile.h"
53
#include "auth.h"
54
#include "log.h"
55
#include "servconf.h"
56
#include "canohost.h"
57
#include "session.h"
58
#include "consolekit.h"
59
60
extern ServerOptions options;
61
extern u_int utmp_len;
62
63
void
64
set_active(const char *cookie)
65
{
66
	DBusError err;
67
	DBusConnection *connection;
68
	DBusMessage *message = NULL, *reply = NULL;
69
	char *sid;
70
	DBusMessageIter iter, subiter;
71
	const char *interface, *property;
72
	dbus_bool_t active;
73
74
	dbus_error_init(&err);
75
	connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err);
76
	if (!connection) {
77
		if (dbus_error_is_set(&err)) {
78
			error("unable to open DBus connection: %s",
79
			    err.message);
80
			dbus_error_free(&err);
81
		}
82
		goto out;
83
	}
84
	dbus_connection_set_exit_on_disconnect(connection, FALSE);
85
86
	message = dbus_message_new_method_call("org.freedesktop.ConsoleKit",
87
	    "/org/freedesktop/ConsoleKit/Manager",
88
	    "org.freedesktop.ConsoleKit.Manager",
89
	    "GetSessionForCookie");
90
	if (!message)
91
		goto out;
92
	if (!dbus_message_append_args(message, DBUS_TYPE_STRING, &cookie,
93
	    DBUS_TYPE_INVALID)) {
94
		if (dbus_error_is_set(&err)) {
95
			error("unable to get current session: %s",
96
			    err.message);
97
			dbus_error_free(&err);
98
		}
99
		goto out;
100
	}
101
102
	dbus_error_init(&err);
103
	reply = dbus_connection_send_with_reply_and_block(connection, message,
104
	    -1, &err);
105
	if (!reply) {
106
		if (dbus_error_is_set(&err)) {
107
			error("unable to get current session: %s",
108
			    err.message);
109
			dbus_error_free(&err);
110
		}
111
		goto out;
112
	}
113
114
	dbus_error_init(&err);
115
	if (!dbus_message_get_args(reply, &err,
116
	    DBUS_TYPE_OBJECT_PATH, &sid,
117
	    DBUS_TYPE_INVALID)) {
118
		if (dbus_error_is_set(&err)) {
119
			error("unable to get current session: %s",
120
			    err.message);
121
			dbus_error_free(&err);
122
		}
123
		goto out;
124
	}
125
	dbus_message_unref(reply);
126
	dbus_message_unref(message);
127
	message = reply = NULL;
128
129
	message = dbus_message_new_method_call("org.freedesktop.ConsoleKit",
130
	    sid, "org.freedesktop.DBus.Properties", "Set");
131
	if (!message)
132
		goto out;
133
	interface = "org.freedesktop.ConsoleKit.Session";
134
	property = "active";
135
	if (!dbus_message_append_args(message,
136
	    DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property,
137
	    DBUS_TYPE_INVALID))
138
		goto out;
139
	dbus_message_iter_init_append(message, &iter);
140
	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
141
	    DBUS_TYPE_BOOLEAN_AS_STRING, &subiter))
142
		goto out;
143
	active = TRUE;
144
	if (!dbus_message_iter_append_basic(&subiter, DBUS_TYPE_BOOLEAN,
145
	    &active))
146
		goto out;
147
	if (!dbus_message_iter_close_container(&iter, &subiter))
148
		goto out;
149
150
	dbus_error_init(&err);
151
	reply = dbus_connection_send_with_reply_and_block(connection, message,
152
	    -1, &err);
153
	if (!reply) {
154
		if (dbus_error_is_set(&err)) {
155
			error("unable to make current session active: %s",
156
			    err.message);
157
			dbus_error_free(&err);
158
		}
159
		goto out;
160
	}
161
162
out:
163
	if (reply)
164
		dbus_message_unref(reply);
165
	if (message)
166
		dbus_message_unref(message);
167
}
168
169
/*
170
 * We pass display separately rather than using s->display because the
171
 * latter is not available in the monitor when using privsep.
172
 */
173
174
char *
175
consolekit_register(Session *s, const char *display)
176
{
177
	DBusError err;
178
	const char *tty = s->tty;
179
	const char *remote_host_name;
180
	dbus_bool_t is_local = FALSE;
181
	const char *cookie = NULL;
182
183
	if (s->ckc) {
184
		debug("already registered with ConsoleKit");
185
		return xstrdup(ck_connector_get_cookie(s->ckc));
186
	}
187
188
	s->ckc = ck_connector_new();
189
	if (!s->ckc) {
190
		error("ck_connector_new failed");
191
		return NULL;
192
	}
193
194
	if (!tty)
195
		tty = "";
196
	if (!display)
197
		display = "";
198
	remote_host_name = get_remote_name_or_ip(utmp_len, options.use_dns);
199
	if (!remote_host_name)
200
		remote_host_name = "";
201
202
	dbus_error_init(&err);
203
	if (!ck_connector_open_session_with_parameters(s->ckc, &err,
204
	    "unix-user", &s->pw->pw_uid,
205
	    "display-device", &tty,
206
	    "x11-display", &display,
207
	    "remote-host-name", &remote_host_name,
208
	    "is-local", &is_local,
209
	    NULL)) {
210
		if (dbus_error_is_set(&err)) {
211
			debug("%s", err.message);
212
			dbus_error_free(&err);
213
		} else {
214
			debug("insufficient privileges or D-Bus / ConsoleKit "
215
			    "not available");
216
		}
217
		return NULL;
218
	}
219
220
	debug("registered uid=%d on tty='%s' with ConsoleKit",
221
	    s->pw->pw_uid, s->tty);
222
223
	cookie = ck_connector_get_cookie(s->ckc);
224
	set_active(cookie);
225
	return xstrdup(cookie);
226
}
227
228
void
229
consolekit_unregister(Session *s)
230
{
231
	if (s->ckc) {
232
		debug("unregistering ConsoleKit session %s",
233
		    ck_connector_get_cookie(s->ckc));
234
		ck_connector_unref(s->ckc);
235
		s->ckc = NULL;
236
	}
237
}
238
239
#endif /* USE_CONSOLEKIT */