xref: /OK3568_Linux_fs/external/xserver/os/xdmauth.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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 global_rho;
66 
67 static Bool
XdmAuthenticationValidator(ARRAY8Ptr privateData,ARRAY8Ptr incomingData,xdmOpCode packet_type)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, &global_rho);
81     }
82     return FALSE;
83 }
84 
85 static Bool
XdmAuthenticationGenerator(ARRAY8Ptr privateData,ARRAY8Ptr outgoingData,xdmOpCode packet_type)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 *) &global_rho, (unsigned char *) &privateKey,
94                       outgoingData->data, 8);
95     }
96     return TRUE;
97 }
98 
99 static Bool
XdmAuthenticationAddAuth(int name_len,const char * name,int data_len,char * data)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
HexToBinary(const char * in,char * out,int len)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
XdmAuthenticationInit(const char * cookie,int cookie_len)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(&global_rho);
154     XdmcpRegisterAuthentication(XdmAuthenticationName, XdmAuthenticationNameLen,
155                                 (char *) &global_rho,
156                                 sizeof(global_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
XdmClientAuthCompare(const XdmClientAuthPtr a,const XdmClientAuthPtr b)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
XdmClientAuthDecode(const unsigned char * plain,XdmClientAuthPtr auth)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
XdmClientAuthTimeout(long now)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 (labs(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
XdmAuthorizationValidate(unsigned char * plain,int length,XdmAuthKeyPtr rho,ClientPtr xclient,const char ** reason)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)
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 (labs(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
XdmAddCookie(unsigned short data_length,const char * data,XID id)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 = global_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 = global_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
XdmCheckCookie(unsigned short cookie_length,const char * cookie,ClientPtr xclient,const char ** reason)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
XdmResetCookie(void)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 int
XdmFromID(XID id,unsigned short * data_lenp,char ** datap)415 XdmFromID(XID id, unsigned short *data_lenp, char **datap)
416 {
417     XdmAuthorizationPtr auth;
418 
419     for (auth = xdmAuth; auth; auth = auth->next) {
420         if (id == auth->id) {
421             *data_lenp = 16;
422             *datap = (char *) &auth->rho;
423             return 1;
424         }
425     }
426     return 0;
427 }
428 
429 int
XdmRemoveCookie(unsigned short data_length,const char * data)430 XdmRemoveCookie(unsigned short data_length, const char *data)
431 {
432     XdmAuthorizationPtr auth;
433     XdmAuthKeyPtr key_bits, rho_bits;
434 
435     switch (data_length) {
436     case 16:
437         rho_bits = (XdmAuthKeyPtr) data;
438         key_bits = (XdmAuthKeyPtr) (data + 8);
439         break;
440 #ifdef XDMCP
441     case 8:
442         rho_bits = &global_rho;
443         key_bits = (XdmAuthKeyPtr) data;
444         break;
445 #endif
446     default:
447         return 0;
448     }
449     for (auth = xdmAuth; auth; auth = auth->next) {
450         if (XdmcpCompareKeys(rho_bits, &auth->rho) &&
451             XdmcpCompareKeys(key_bits, &auth->key)) {
452             xdmAuth = auth->next;
453             free(auth);
454             return 1;
455         }
456     }
457     return 0;
458 }
459 
460 #endif
461