Apply a patch for fixing TDIS-5990 (CVE-2013-1940 allow physically proximate attacker...
[framework/uifw/xorg/server/xorg-server.git] / os / xdmauth.c
1 /*
2
3 Copyright 1988, 1998  The Open Group
4
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of The Open Group shall
23 not be used in advertising or otherwise to promote the sale, use or
24 other dealings in this Software without prior written authorization
25 from 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
52 static 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
61 static XdmAuthKeyRec privateKey;
62 static char XdmAuthenticationName[] = "XDM-AUTHENTICATION-1";
63
64 #define XdmAuthenticationNameLen (sizeof XdmAuthenticationName - 1)
65 static XdmAuthKeyRec rho;
66
67 static Bool
68 XdmAuthenticationValidator(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
85 static Bool
86 XdmAuthenticationGenerator(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
99 static Bool
100 XdmAuthenticationAddAuth(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
117 static int
118 HexToBinary(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
139 void
140 XdmAuthenticationInit(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 */
165 typedef struct _XdmAuthorization {
166     struct _XdmAuthorization *next;
167     XdmAuthKeyRec rho;
168     XdmAuthKeyRec key;
169     XID id;
170 } XdmAuthorizationRec, *XdmAuthorizationPtr;
171
172 static XdmAuthorizationPtr xdmAuth;
173
174 typedef struct _XdmClientAuth {
175     struct _XdmClientAuth *next;
176     XdmAuthKeyRec rho;
177     char client[6];
178     long time;
179 } XdmClientAuthRec, *XdmClientAuthPtr;
180
181 static XdmClientAuthPtr xdmClients;
182 static long clockOffset;
183 static Bool gotClock;
184
185 #define TwentyMinutes   (20 * 60)
186 #define TwentyFiveMinutes (25 * 60)
187
188 static Bool
189 XdmClientAuthCompare(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
201 static void
202 XdmClientAuthDecode(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
222 static void
223 XdmClientAuthTimeout(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
242 static XdmClientAuthPtr
243 XdmAuthorizationValidate(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
319 int
320 XdmAddCookie(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
365 XID
366 XdmCheckCookie(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
395 int
396 XdmResetCookie(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
414 XID
415 XdmToID(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
441 int
442 XdmFromID(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
456 int
457 XdmRemoveCookie(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