]> Dogcows Code - chaz/openbox/blob - tools/gdm-control/gdm-control.c
Merge branch 'backport' into work
[chaz/openbox] / tools / gdm-control / gdm-control.c
1 #include <string.h>
2 #include <stdio.h>
3 #include <assert.h>
4 #include <errno.h>
5 #include <unistd.h>
6 #include <sys/socket.h>
7 #include <sys/un.h>
8
9 #include <X11/Xlib.h>
10 #include <X11/Xauth.h>
11
12 #include <glib.h>
13
14 typedef enum
15 {
16 INVALID,
17 NONE,
18 SHUTDOWN,
19 REBOOT,
20 SUSPEND,
21 SWITCHUSER
22 } Action;
23
24 #define GDM_PROTOCOL_SOCKET_PATH1 "/var/run/gdm_socket"
25 #define GDM_PROTOCOL_SOCKET_PATH2 "/tmp/.gdm_socket"
26
27 #define GDM_PROTOCOL_MSG_CLOSE "CLOSE"
28 #define GDM_PROTOCOL_MSG_VERSION "VERSION"
29 #define GDM_PROTOCOL_MSG_AUTHENTICATE "AUTH_LOCAL"
30 #define GDM_PROTOCOL_MSG_QUERY_ACTION "QUERY_LOGOUT_ACTION"
31 #define GDM_PROTOCOL_MSG_SET_ACTION "SET_SAFE_LOGOUT_ACTION"
32 #define GDM_PROTOCOL_MSG_FLEXI_XSERVER "FLEXI_XSERVER"
33
34 #define GDM_ACTION_STR_NONE GDM_PROTOCOL_MSG_SET_ACTION" NONE"
35 #define GDM_ACTION_STR_SHUTDOWN GDM_PROTOCOL_MSG_SET_ACTION" HALT"
36 #define GDM_ACTION_STR_REBOOT GDM_PROTOCOL_MSG_SET_ACTION" REBOOT"
37 #define GDM_ACTION_STR_SUSPEND GDM_PROTOCOL_MSG_SET_ACTION" SUSPEND"
38
39 #define GDM_MIT_MAGIC_COOKIE_LEN 16
40
41 static int fd = 0;
42
43 static void gdm_disconnect()
44 {
45 if (fd > 0)
46 close(fd);
47 fd = 0;
48 }
49
50 static char* get_display_number(void)
51 {
52 char *display_name;
53 char *retval;
54 char *p;
55
56 display_name = XDisplayName(NULL);
57
58 p = strchr(display_name, ':');
59 if (!p)
60 return g_strdup ("0");
61
62 while (*p == ':') p++;
63
64 retval = g_strdup (p);
65
66 p = strchr (retval, '.');
67 if (p != NULL)
68 *p = '\0';
69
70 return retval;
71 }
72
73 static char* gdm_send_protocol_msg (const char *msg)
74 {
75 GString *retval;
76 char buf[256];
77 char *p;
78 int len;
79
80 p = g_strconcat(msg, "\n", NULL);
81 if (write (fd, p, strlen(p)) < 0) {
82 g_free (p);
83
84 g_warning ("Failed to send message to GDM: %s",
85 g_strerror (errno));
86 return NULL;
87 }
88 g_free (p);
89
90 p = NULL;
91 retval = NULL;
92 while ((len = read(fd, buf, sizeof(buf) - 1)) > 0) {
93 buf[len] = '\0';
94
95 if (!retval)
96 retval = g_string_new(buf);
97 else
98 retval = g_string_append(retval, buf);
99
100 if ((p = strchr(retval->str, '\n')))
101 break;
102 }
103
104 if (p) *p = '\0';
105
106 return retval ? g_string_free(retval, FALSE) : NULL;
107 }
108
109 static gboolean gdm_authenticate()
110 {
111 FILE *f;
112 Xauth *xau;
113 const char *xau_path;
114 char *display_number;
115 gboolean retval;
116
117 if (!(xau_path = XauFileName()))
118 return FALSE;
119
120 if (!(f = fopen(xau_path, "r")))
121 return FALSE;
122
123 retval = FALSE;
124 display_number = get_display_number();
125
126 while ((xau = XauReadAuth(f))) {
127 char buffer[40]; /* 2*16 == 32, so 40 is enough */
128 char *msg;
129 char *response;
130 int i;
131
132 if (xau->family != FamilyLocal ||
133 strncmp (xau->number, display_number, xau->number_length) ||
134 strncmp (xau->name, "MIT-MAGIC-COOKIE-1", xau->name_length) ||
135 xau->data_length != GDM_MIT_MAGIC_COOKIE_LEN)
136 {
137 XauDisposeAuth(xau);
138 continue;
139 }
140
141 for (i = 0; i < GDM_MIT_MAGIC_COOKIE_LEN; i++)
142 g_snprintf(buffer + 2*i, 3, "%02x", (guint)(guchar)xau->data[i]);
143
144 XauDisposeAuth(xau);
145
146 msg = g_strdup_printf(GDM_PROTOCOL_MSG_AUTHENTICATE " %s", buffer);
147 response = gdm_send_protocol_msg(msg);
148 g_free (msg);
149
150 if (response && !strcmp(response, "OK")) {
151 /*auth_cookie = g_strdup(buffer);*/
152 g_free(response);
153 retval = TRUE;
154 break;
155 }
156
157 g_free (response);
158 }
159
160 fclose(f);
161 return retval;
162 }
163
164 static gboolean gdm_connect()
165 {
166 struct sockaddr_un addr;
167 char *response;
168
169 assert(fd <= 0);
170
171 fd = socket(AF_UNIX, SOCK_STREAM, 0);
172 if (fd < 0) {
173 g_warning("Failed to create GDM socket: %s", g_strerror (errno));
174 gdm_disconnect();
175 return FALSE;
176 }
177
178 if (g_file_test(GDM_PROTOCOL_SOCKET_PATH1, G_FILE_TEST_EXISTS))
179 strcpy(addr.sun_path, GDM_PROTOCOL_SOCKET_PATH1);
180 else
181 strcpy(addr.sun_path, GDM_PROTOCOL_SOCKET_PATH2);
182
183 addr.sun_family = AF_UNIX;
184
185 if (connect(fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) {
186 g_warning("Failed to establish a connection with GDM: %s",
187 g_strerror(errno));
188 gdm_disconnect();
189 return FALSE;
190 }
191
192 response = gdm_send_protocol_msg(GDM_PROTOCOL_MSG_VERSION);
193 if (!response || strncmp(response, "GDM ", strlen("GDM ") != 0)) {
194 g_free(response);
195
196 g_warning("Failed to get protocol version from GDM");
197 gdm_disconnect();
198 return FALSE;
199 }
200 g_free(response);
201
202 if (!gdm_authenticate()) {
203 g_warning("Failed to authenticate with GDM");
204 gdm_disconnect();
205 return FALSE;
206 }
207
208 return TRUE;
209 }
210
211 int main(int argc, char **argv)
212 {
213 int i;
214 Action a = INVALID;
215
216 for (i = 1; i < argc; ++i) {
217 if (!strcmp(argv[i], "--help")) {
218 a = INVALID;
219 break;
220 }
221 if (!strcmp(argv[i], "--none")) {
222 a = NONE;
223 break;
224 }
225 if (!strcmp(argv[i], "--shutdown")) {
226 a = SHUTDOWN;
227 break;
228 }
229 if (!strcmp(argv[i], "--reboot")) {
230 a = REBOOT;
231 break;
232 }
233 if (!strcmp(argv[i], "--suspend")) {
234 a = SUSPEND;
235 break;
236 }
237 if (!strcmp(argv[i], "--switch-user")) {
238 a = SWITCHUSER;
239 break;
240 }
241 }
242
243 if (!a) {
244 printf("Usage: gdm-control ACTION\n\n");
245 printf("Actions:\n");
246 printf(" --help Display this help and exit\n");
247 printf(" --none Do nothing special when the current session ends\n");
248 printf(" --shutdown Shutdown the computer when the current session ends\n");
249 printf(" --reboot Reboot the computer when the current session ends\n");
250 printf(" --suspend Suspend the computer when the current session ends\n");
251 printf(" --switch-user Log in as a new user (this works immediately)\n\n");
252 return 0;
253 }
254
255 {
256 char *d, *response;
257 const char *action_string;
258
259 d = XDisplayName(NULL);
260 if (!d) {
261 fprintf(stderr,
262 "Unable to fina an X display specified by the DISPLAY "
263 "environment variable. Ensure that it is set correctly.");
264 return 1;
265 }
266
267 switch (a) {
268 case NONE:
269 action_string = GDM_ACTION_STR_NONE;
270 break;
271 case SHUTDOWN:
272 action_string = GDM_ACTION_STR_SHUTDOWN;
273 break;
274 case REBOOT:
275 action_string = GDM_ACTION_STR_REBOOT;
276 break;
277 case SUSPEND:
278 action_string = GDM_ACTION_STR_SUSPEND;
279 break;
280 case SWITCHUSER:
281 action_string = GDM_PROTOCOL_MSG_FLEXI_XSERVER;
282 break;
283 default:
284 assert(0);
285 }
286
287 if (gdm_connect()) {
288 response = gdm_send_protocol_msg(action_string);
289 g_free(response);
290 gdm_disconnect();
291 }
292 }
293
294 return 0;
295 }
This page took 0.052718 seconds and 4 git commands to generate.