Imported Upstream version 1.15.1
[deb_xorg-server.git] / os / xdmauth.c
CommitLineData
a09e091a
JB
1/*
2
3Copyright 1988, 1998 The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from The Open Group.
26
27*/
28
29/*
30 * XDM-AUTHENTICATION-1 (XDMCP authentication) and
31 * XDM-AUTHORIZATION-1 (client authorization) protocols
32 *
33 * Author: Keith Packard, MIT X Consortium
34 */
35
36#ifdef HAVE_DIX_CONFIG_H
37#include <dix-config.h>
38#endif
39
40#include <stdio.h>
41#include <X11/X.h>
42#define XSERV_t
43#define TRANS_SERVER
44#define TRANS_REOPEN
45#include <X11/Xtrans/Xtrans.h>
46#include "os.h"
47#include "osdep.h"
48#include "dixstruct.h"
49
50#ifdef HASXDMAUTH
51
52static Bool authFromXDMCP;
53
54#ifdef XDMCP
55#include <X11/Xmd.h>
56#undef REQUEST
57#include <X11/Xdmcp.h>
58
59/* XDM-AUTHENTICATION-1 */
60
61static XdmAuthKeyRec privateKey;
62static char XdmAuthenticationName[] = "XDM-AUTHENTICATION-1";
63
64#define XdmAuthenticationNameLen (sizeof XdmAuthenticationName - 1)
65static XdmAuthKeyRec rho;
66
67static Bool
68XdmAuthenticationValidator(ARRAY8Ptr privateData, ARRAY8Ptr incomingData,
69 xdmOpCode packet_type)
70{
71 XdmAuthKeyPtr incoming;
72
73 XdmcpUnwrap(incomingData->data, (unsigned char *) &privateKey,
74 incomingData->data, incomingData->length);
75 if (packet_type == ACCEPT) {
76 if (incomingData->length != 8)
77 return FALSE;
78 incoming = (XdmAuthKeyPtr) incomingData->data;
79 XdmcpDecrementKey(incoming);
80 return XdmcpCompareKeys(incoming, &rho);
81 }
82 return FALSE;
83}
84
85static Bool
86XdmAuthenticationGenerator(ARRAY8Ptr privateData, ARRAY8Ptr outgoingData,
87 xdmOpCode packet_type)
88{
89 outgoingData->length = 0;
90 outgoingData->data = 0;
91 if (packet_type == REQUEST) {
92 if (XdmcpAllocARRAY8(outgoingData, 8))
93 XdmcpWrap((unsigned char *) &rho, (unsigned char *) &privateKey,
94 outgoingData->data, 8);
95 }
96 return TRUE;
97}
98
99static Bool
100XdmAuthenticationAddAuth(int name_len, const char *name,
101 int data_len, char *data)
102{
103 Bool ret;
104
105 XdmcpUnwrap((unsigned char *) data, (unsigned char *) &privateKey,
106 (unsigned char *) data, data_len);
107 authFromXDMCP = TRUE;
108 ret = AddAuthorization(name_len, name, data_len, data);
109 authFromXDMCP = FALSE;
110 return ret;
111}
112
113#define atox(c) ('0' <= c && c <= '9' ? c - '0' : \
114 'a' <= c && c <= 'f' ? c - 'a' + 10 : \
115 'A' <= c && c <= 'F' ? c - 'A' + 10 : -1)
116
117static int
118HexToBinary(const char *in, char *out, int len)
119{
120 int top, bottom;
121
122 while (len > 0) {
123 top = atox(in[0]);
124 if (top == -1)
125 return 0;
126 bottom = atox(in[1]);
127 if (bottom == -1)
128 return 0;
129 *out++ = (top << 4) | bottom;
130 in += 2;
131 len -= 2;
132 }
133 if (len)
134 return 0;
135 *out++ = '\0';
136 return 1;
137}
138
139void
140XdmAuthenticationInit(const char *cookie, int cookie_len)
141{
142 memset(privateKey.data, 0, 8);
143 if (!strncmp(cookie, "0x", 2) || !strncmp(cookie, "0X", 2)) {
144 if (cookie_len > 2 + 2 * 8)
145 cookie_len = 2 + 2 * 8;
146 HexToBinary(cookie + 2, (char *) privateKey.data, cookie_len - 2);
147 }
148 else {
149 if (cookie_len > 7)
150 cookie_len = 7;
151 memmove(privateKey.data + 1, cookie, cookie_len);
152 }
153 XdmcpGenerateKey(&rho);
154 XdmcpRegisterAuthentication(XdmAuthenticationName, XdmAuthenticationNameLen,
155 (char *) &rho,
156 sizeof(rho),
157 (ValidatorFunc) XdmAuthenticationValidator,
158 (GeneratorFunc) XdmAuthenticationGenerator,
159 (AddAuthorFunc) XdmAuthenticationAddAuth);
160}
161
162#endif /* XDMCP */
163
164/* XDM-AUTHORIZATION-1 */
165typedef struct _XdmAuthorization {
166 struct _XdmAuthorization *next;
167 XdmAuthKeyRec rho;
168 XdmAuthKeyRec key;
169 XID id;
170} XdmAuthorizationRec, *XdmAuthorizationPtr;
171
172static XdmAuthorizationPtr xdmAuth;
173
174typedef struct _XdmClientAuth {
175 struct _XdmClientAuth *next;
176 XdmAuthKeyRec rho;
177 char client[6];
178 long time;
179} XdmClientAuthRec, *XdmClientAuthPtr;
180
181static XdmClientAuthPtr xdmClients;
182static long clockOffset;
183static Bool gotClock;
184
185#define TwentyMinutes (20 * 60)
186#define TwentyFiveMinutes (25 * 60)
187
188static Bool
189XdmClientAuthCompare(const XdmClientAuthPtr a, const XdmClientAuthPtr b)
190{
191 int i;
192
193 if (!XdmcpCompareKeys(&a->rho, &b->rho))
194 return FALSE;
195 for (i = 0; i < 6; i++)
196 if (a->client[i] != b->client[i])
197 return FALSE;
198 return a->time == b->time;
199}
200
201static void
202XdmClientAuthDecode(const unsigned char *plain, XdmClientAuthPtr auth)
203{
204 int i, j;
205
206 j = 0;
207 for (i = 0; i < 8; i++) {
208 auth->rho.data[i] = plain[j];
209 ++j;
210 }
211 for (i = 0; i < 6; i++) {
212 auth->client[i] = plain[j];
213 ++j;
214 }
215 auth->time = 0;
216 for (i = 0; i < 4; i++) {
217 auth->time |= plain[j] << ((3 - i) << 3);
218 j++;
219 }
220}
221
222static void
223XdmClientAuthTimeout(long now)
224{
225 XdmClientAuthPtr client, next, prev;
226
227 prev = 0;
228 for (client = xdmClients; client; client = next) {
229 next = client->next;
230 if (abs(now - client->time) > TwentyFiveMinutes) {
231 if (prev)
232 prev->next = next;
233 else
234 xdmClients = next;
235 free(client);
236 }
237 else
238 prev = client;
239 }
240}
241
242static XdmClientAuthPtr
243XdmAuthorizationValidate(unsigned char *plain, int length,
244 XdmAuthKeyPtr rho, ClientPtr xclient,
245 const char **reason)
246{
247 XdmClientAuthPtr client, existing;
248 long now;
249 int i;
250
251 if (length != (192 / 8)) {
252 if (reason)
253 *reason = "Bad XDM authorization key length";
254 return NULL;
255 }
256 client = malloc(sizeof(XdmClientAuthRec));
257 if (!client)
258 return NULL;
259 XdmClientAuthDecode(plain, client);
260 if (!XdmcpCompareKeys(&client->rho, rho)) {
261 free(client);
262 if (reason)
263 *reason = "Invalid XDM-AUTHORIZATION-1 key (failed key comparison)";
264 return NULL;
265 }
266 for (i = 18; i < 24; i++)
267 if (plain[i] != 0) {
268 free(client);
269 if (reason)
270 *reason = "Invalid XDM-AUTHORIZATION-1 key (failed NULL check)";
271 return NULL;
272 }
273 if (xclient) {
274 int family, addr_len;
275 Xtransaddr *addr;
276
277 if (_XSERVTransGetPeerAddr(((OsCommPtr) xclient->osPrivate)->trans_conn,
278 &family, &addr_len, &addr) == 0
279 && _XSERVTransConvertAddress(&family, &addr_len, &addr) == 0) {
280#if defined(TCPCONN) || defined(STREAMSCONN)
281 if (family == FamilyInternet &&
282 memcmp((char *) addr, client->client, 4) != 0) {
283 free(client);
284 free(addr);
285 if (reason)
286 *reason =
287 "Invalid XDM-AUTHORIZATION-1 key (failed address comparison)";
288 return NULL;
289
290 }
291#endif
292 free(addr);
293 }
294 }
295 now = time(0);
296 if (!gotClock) {
297 clockOffset = client->time - now;
298 gotClock = TRUE;
299 }
300 now += clockOffset;
301 XdmClientAuthTimeout(now);
302 if (abs(client->time - now) > TwentyMinutes) {
303 free(client);
304 if (reason)
305 *reason = "Excessive XDM-AUTHORIZATION-1 time offset";
306 return NULL;
307 }
308 for (existing = xdmClients; existing; existing = existing->next) {
309 if (XdmClientAuthCompare(existing, client)) {
310 free(client);
311 if (reason)
312 *reason = "XDM authorization key matches an existing client!";
313 return NULL;
314 }
315 }
316 return client;
317}
318
319int
320XdmAddCookie(unsigned short data_length, const char *data, XID id)
321{
322 XdmAuthorizationPtr new;
323 unsigned char *rho_bits, *key_bits;
324
325 switch (data_length) {
326 case 16: /* auth from files is 16 bytes long */
327#ifdef XDMCP
328 if (authFromXDMCP) {
329 /* R5 xdm sent bogus authorization data in the accept packet,
330 * but we can recover */
331 rho_bits = rho.data;
332 key_bits = (unsigned char *) data;
333 key_bits[0] = '\0';
334 }
335 else
336#endif
337 {
338 rho_bits = (unsigned char *) data;
339 key_bits = (unsigned char *) (data + 8);
340 }
341 break;
342#ifdef XDMCP
343 case 8: /* auth from XDMCP is 8 bytes long */
344 rho_bits = rho.data;
345 key_bits = (unsigned char *) data;
346 break;
347#endif
348 default:
349 return 0;
350 }
351 /* the first octet of the key must be zero */
352 if (key_bits[0] != '\0')
353 return 0;
354 new = malloc(sizeof(XdmAuthorizationRec));
355 if (!new)
356 return 0;
357 new->next = xdmAuth;
358 xdmAuth = new;
359 memmove(new->key.data, key_bits, (int) 8);
360 memmove(new->rho.data, rho_bits, (int) 8);
361 new->id = id;
362 return 1;
363}
364
365XID
366XdmCheckCookie(unsigned short cookie_length, const char *cookie,
367 ClientPtr xclient, const char **reason)
368{
369 XdmAuthorizationPtr auth;
370 XdmClientAuthPtr client;
371 unsigned char *plain;
372
373 /* Auth packets must be a multiple of 8 bytes long */
374 if (cookie_length & 7)
375 return (XID) -1;
376 plain = malloc(cookie_length);
377 if (!plain)
378 return (XID) -1;
379 for (auth = xdmAuth; auth; auth = auth->next) {
380 XdmcpUnwrap((unsigned char *) cookie, (unsigned char *) &auth->key,
381 plain, cookie_length);
382 if ((client =
383 XdmAuthorizationValidate(plain, cookie_length, &auth->rho, xclient,
384 reason)) != NULL) {
385 client->next = xdmClients;
386 xdmClients = client;
387 free(plain);
388 return auth->id;
389 }
390 }
391 free(plain);
392 return (XID) -1;
393}
394
395int
396XdmResetCookie(void)
397{
398 XdmAuthorizationPtr auth, next_auth;
399 XdmClientAuthPtr client, next_client;
400
401 for (auth = xdmAuth; auth; auth = next_auth) {
402 next_auth = auth->next;
403 free(auth);
404 }
405 xdmAuth = 0;
406 for (client = xdmClients; client; client = next_client) {
407 next_client = client->next;
408 free(client);
409 }
410 xdmClients = (XdmClientAuthPtr) 0;
411 return 1;
412}
413
414XID
415XdmToID(unsigned short cookie_length, char *cookie)
416{
417 XdmAuthorizationPtr auth;
418 XdmClientAuthPtr client;
419 unsigned char *plain;
420
421 plain = malloc(cookie_length);
422 if (!plain)
423 return (XID) -1;
424 for (auth = xdmAuth; auth; auth = auth->next) {
425 XdmcpUnwrap((unsigned char *) cookie, (unsigned char *) &auth->key,
426 plain, cookie_length);
427 if ((client =
428 XdmAuthorizationValidate(plain, cookie_length, &auth->rho, NULL,
429 NULL)) != NULL) {
430 free(client);
431 free(cookie);
432 free(plain);
433 return auth->id;
434 }
435 }
436 free(cookie);
437 free(plain);
438 return (XID) -1;
439}
440
441int
442XdmFromID(XID id, unsigned short *data_lenp, char **datap)
443{
444 XdmAuthorizationPtr auth;
445
446 for (auth = xdmAuth; auth; auth = auth->next) {
447 if (id == auth->id) {
448 *data_lenp = 16;
449 *datap = (char *) &auth->rho;
450 return 1;
451 }
452 }
453 return 0;
454}
455
456int
457XdmRemoveCookie(unsigned short data_length, const char *data)
458{
459 XdmAuthorizationPtr auth;
460 XdmAuthKeyPtr key_bits, rho_bits;
461
462 switch (data_length) {
463 case 16:
464 rho_bits = (XdmAuthKeyPtr) data;
465 key_bits = (XdmAuthKeyPtr) (data + 8);
466 break;
467#ifdef XDMCP
468 case 8:
469 rho_bits = &rho;
470 key_bits = (XdmAuthKeyPtr) data;
471 break;
472#endif
473 default:
474 return 0;
475 }
476 for (auth = xdmAuth; auth; auth = auth->next) {
477 if (XdmcpCompareKeys(rho_bits, &auth->rho) &&
478 XdmcpCompareKeys(key_bits, &auth->key)) {
479 xdmAuth = auth->next;
480 free(auth);
481 return 1;
482 }
483 }
484 return 0;
485}
486
487#endif