ci: Check for DDXen to be built
[xserver.git] / os / xdmauth.c
blob3a676e18807f961eacc20c59ea4f1d10e4365251
1 /*
3 Copyright 1988, 1998 The Open Group
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.
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
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.
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.
30 * XDM-AUTHENTICATION-1 (XDMCP authentication) and
31 * XDM-AUTHORIZATION-1 (client authorization) protocols
33 * Author: Keith Packard, MIT X Consortium
36 #include <dix-config.h>
38 #include <stdio.h>
39 #include <X11/X.h>
40 #define XSERV_t
41 #define TRANS_SERVER
42 #define TRANS_REOPEN
43 #include <X11/Xtrans/Xtrans.h>
45 #include "os/auth.h"
47 #include "os.h"
48 #include "osdep.h"
49 #include "xdmcp.h"
50 #include "xdmauth.h"
51 #include "dixstruct.h"
53 #ifdef HASXDMAUTH
55 static Bool authFromXDMCP;
57 #ifdef XDMCP
58 #include <X11/Xmd.h>
59 #undef REQUEST
60 #include <X11/Xdmcp.h>
62 /* XDM-AUTHENTICATION-1 */
64 static XdmAuthKeyRec privateKey;
65 static char XdmAuthenticationName[] = "XDM-AUTHENTICATION-1";
67 #define XdmAuthenticationNameLen (sizeof XdmAuthenticationName - 1)
68 static XdmAuthKeyRec global_rho;
70 static Bool
71 XdmAuthenticationValidator(ARRAY8Ptr privateData, ARRAY8Ptr incomingData,
72 xdmOpCode packet_type)
74 XdmAuthKeyPtr incoming;
76 XdmcpUnwrap(incomingData->data, (unsigned char *) &privateKey,
77 incomingData->data, incomingData->length);
78 if (packet_type == ACCEPT) {
79 if (incomingData->length != 8)
80 return FALSE;
81 incoming = (XdmAuthKeyPtr) incomingData->data;
82 XdmcpDecrementKey(incoming);
83 return XdmcpCompareKeys(incoming, &global_rho);
85 return FALSE;
88 static Bool
89 XdmAuthenticationGenerator(ARRAY8Ptr privateData, ARRAY8Ptr outgoingData,
90 xdmOpCode packet_type)
92 outgoingData->length = 0;
93 outgoingData->data = 0;
94 if (packet_type == REQUEST) {
95 if (XdmcpAllocARRAY8(outgoingData, 8))
96 XdmcpWrap((unsigned char *) &global_rho, (unsigned char *) &privateKey,
97 outgoingData->data, 8);
99 return TRUE;
102 static Bool
103 XdmAuthenticationAddAuth(int name_len, const char *name,
104 int data_len, char *data)
106 Bool ret;
108 XdmcpUnwrap((unsigned char *) data, (unsigned char *) &privateKey,
109 (unsigned char *) data, data_len);
110 authFromXDMCP = TRUE;
111 ret = AddAuthorization(name_len, name, data_len, data);
112 authFromXDMCP = FALSE;
113 return ret;
116 #define atox(c) ('0' <= c && c <= '9' ? c - '0' : \
117 'a' <= c && c <= 'f' ? c - 'a' + 10 : \
118 'A' <= c && c <= 'F' ? c - 'A' + 10 : -1)
120 static int
121 HexToBinary(const char *in, char *out, int len)
123 int top, bottom;
125 while (len > 0) {
126 top = atox(in[0]);
127 if (top == -1)
128 return 0;
129 bottom = atox(in[1]);
130 if (bottom == -1)
131 return 0;
132 *out++ = (top << 4) | bottom;
133 in += 2;
134 len -= 2;
136 if (len)
137 return 0;
138 *out++ = '\0';
139 return 1;
142 void
143 XdmAuthenticationInit(const char *cookie, int cookie_len)
145 memset(privateKey.data, 0, 8);
146 if (!strncmp(cookie, "0x", 2) || !strncmp(cookie, "0X", 2)) {
147 if (cookie_len > 2 + 2 * 8)
148 cookie_len = 2 + 2 * 8;
149 HexToBinary(cookie + 2, (char *) privateKey.data, cookie_len - 2);
151 else {
152 if (cookie_len > 7)
153 cookie_len = 7;
154 memmove(privateKey.data + 1, cookie, cookie_len);
156 XdmcpGenerateKey(&global_rho);
157 XdmcpRegisterAuthentication(XdmAuthenticationName, XdmAuthenticationNameLen,
158 (char *) &global_rho,
159 sizeof(global_rho),
160 (ValidatorFunc) XdmAuthenticationValidator,
161 (GeneratorFunc) XdmAuthenticationGenerator,
162 (AddAuthorFunc) XdmAuthenticationAddAuth);
165 #endif /* XDMCP */
167 /* XDM-AUTHORIZATION-1 */
168 typedef struct _XdmAuthorization {
169 struct _XdmAuthorization *next;
170 XdmAuthKeyRec rho;
171 XdmAuthKeyRec key;
172 XID id;
173 } XdmAuthorizationRec, *XdmAuthorizationPtr;
175 static XdmAuthorizationPtr xdmAuth;
177 typedef struct _XdmClientAuth {
178 struct _XdmClientAuth *next;
179 XdmAuthKeyRec rho;
180 char client[6];
181 long time;
182 } XdmClientAuthRec, *XdmClientAuthPtr;
184 static XdmClientAuthPtr xdmClients;
185 static long clockOffset;
186 static Bool gotClock;
188 #define TwentyMinutes (20 * 60)
189 #define TwentyFiveMinutes (25 * 60)
191 static Bool
192 XdmClientAuthCompare(const XdmClientAuthPtr a, const XdmClientAuthPtr b)
194 int i;
196 if (!XdmcpCompareKeys(&a->rho, &b->rho))
197 return FALSE;
198 for (i = 0; i < 6; i++)
199 if (a->client[i] != b->client[i])
200 return FALSE;
201 return a->time == b->time;
204 static void
205 XdmClientAuthDecode(const unsigned char *plain, XdmClientAuthPtr auth)
207 int i, j;
209 j = 0;
210 for (i = 0; i < 8; i++) {
211 auth->rho.data[i] = plain[j];
212 ++j;
214 for (i = 0; i < 6; i++) {
215 auth->client[i] = plain[j];
216 ++j;
218 auth->time = 0;
219 for (i = 0; i < 4; i++) {
220 auth->time |= plain[j] << ((3 - i) << 3);
221 j++;
225 static void
226 XdmClientAuthTimeout(long now)
228 XdmClientAuthPtr client, next, prev;
230 prev = 0;
231 for (client = xdmClients; client; client = next) {
232 next = client->next;
233 if (labs(now - client->time) > TwentyFiveMinutes) {
234 if (prev)
235 prev->next = next;
236 else
237 xdmClients = next;
238 free(client);
240 else
241 prev = client;
245 static XdmClientAuthPtr
246 XdmAuthorizationValidate(unsigned char *plain, int length,
247 XdmAuthKeyPtr rho, ClientPtr xclient,
248 const char **reason)
250 XdmClientAuthPtr client, existing;
251 long now;
252 int i;
254 if (length != (192 / 8)) {
255 if (reason)
256 *reason = "Bad XDM authorization key length";
257 return NULL;
259 client = malloc(sizeof(XdmClientAuthRec));
260 if (!client)
261 return NULL;
262 XdmClientAuthDecode(plain, client);
263 if (!XdmcpCompareKeys(&client->rho, rho)) {
264 free(client);
265 if (reason)
266 *reason = "Invalid XDM-AUTHORIZATION-1 key (failed key comparison)";
267 return NULL;
269 for (i = 18; i < 24; i++)
270 if (plain[i] != 0) {
271 free(client);
272 if (reason)
273 *reason = "Invalid XDM-AUTHORIZATION-1 key (failed NULL check)";
274 return NULL;
276 if (xclient) {
277 int family, addr_len;
278 Xtransaddr *addr;
280 if (_XSERVTransGetPeerAddr(((OsCommPtr) xclient->osPrivate)->trans_conn,
281 &family, &addr_len, &addr) == 0
282 && _XSERVTransConvertAddress(&family, &addr_len, &addr) == 0) {
283 #if defined(TCPCONN)
284 if (family == FamilyInternet &&
285 memcmp((char *) addr, client->client, 4) != 0) {
286 free(client);
287 free(addr);
288 if (reason)
289 *reason =
290 "Invalid XDM-AUTHORIZATION-1 key (failed address comparison)";
291 return NULL;
294 #endif
295 free(addr);
298 now = time(0);
299 if (!gotClock) {
300 clockOffset = client->time - now;
301 gotClock = TRUE;
303 now += clockOffset;
304 XdmClientAuthTimeout(now);
305 if (labs(client->time - now) > TwentyMinutes) {
306 free(client);
307 if (reason)
308 *reason = "Excessive XDM-AUTHORIZATION-1 time offset";
309 return NULL;
311 for (existing = xdmClients; existing; existing = existing->next) {
312 if (XdmClientAuthCompare(existing, client)) {
313 free(client);
314 if (reason)
315 *reason = "XDM authorization key matches an existing client!";
316 return NULL;
319 return client;
323 XdmAddCookie(unsigned short data_length, const char *data, XID id)
325 XdmAuthorizationPtr new;
326 unsigned char *rho_bits, *key_bits;
328 switch (data_length) {
329 case 16: /* auth from files is 16 bytes long */
330 #ifdef XDMCP
331 if (authFromXDMCP) {
332 /* R5 xdm sent bogus authorization data in the accept packet,
333 * but we can recover */
334 rho_bits = global_rho.data;
335 key_bits = (unsigned char *) data;
336 key_bits[0] = '\0';
338 else
339 #endif
341 rho_bits = (unsigned char *) data;
342 key_bits = (unsigned char *) (data + 8);
344 break;
345 #ifdef XDMCP
346 case 8: /* auth from XDMCP is 8 bytes long */
347 rho_bits = global_rho.data;
348 key_bits = (unsigned char *) data;
349 break;
350 #endif
351 default:
352 return 0;
354 /* the first octet of the key must be zero */
355 if (key_bits[0] != '\0')
356 return 0;
357 new = malloc(sizeof(XdmAuthorizationRec));
358 if (!new)
359 return 0;
360 new->next = xdmAuth;
361 xdmAuth = new;
362 memcpy(new->key.data, key_bits, 8);
363 memcpy(new->rho.data, rho_bits, 8);
364 new->id = id;
365 return 1;
369 XdmCheckCookie(unsigned short cookie_length, const char *cookie,
370 ClientPtr xclient, const char **reason)
372 XdmAuthorizationPtr auth;
373 XdmClientAuthPtr client;
374 unsigned char *plain;
376 /* Auth packets must be a multiple of 8 bytes long */
377 if (cookie_length & 7)
378 return (XID) -1;
379 plain = malloc(cookie_length);
380 if (!plain)
381 return (XID) -1;
382 for (auth = xdmAuth; auth; auth = auth->next) {
383 XdmcpUnwrap((unsigned char *) cookie, (unsigned char *) &auth->key,
384 plain, cookie_length);
385 if ((client =
386 XdmAuthorizationValidate(plain, cookie_length, &auth->rho, xclient,
387 reason)) != NULL) {
388 client->next = xdmClients;
389 xdmClients = client;
390 free(plain);
391 return auth->id;
394 free(plain);
395 return (XID) -1;
399 XdmResetCookie(void)
401 XdmAuthorizationPtr auth, next_auth;
402 XdmClientAuthPtr client, next_client;
404 for (auth = xdmAuth; auth; auth = next_auth) {
405 next_auth = auth->next;
406 free(auth);
408 xdmAuth = 0;
409 for (client = xdmClients; client; client = next_client) {
410 next_client = client->next;
411 free(client);
413 xdmClients = (XdmClientAuthPtr) 0;
414 return 1;
418 XdmFromID(XID id, unsigned short *data_lenp, char **datap)
420 XdmAuthorizationPtr auth;
422 for (auth = xdmAuth; auth; auth = auth->next) {
423 if (id == auth->id) {
424 *data_lenp = 16;
425 *datap = (char *) &auth->rho;
426 return 1;
429 return 0;
433 XdmRemoveCookie(unsigned short data_length, const char *data)
435 XdmAuthorizationPtr auth;
436 XdmAuthKeyPtr key_bits, rho_bits;
438 switch (data_length) {
439 case 16:
440 rho_bits = (XdmAuthKeyPtr) data;
441 key_bits = (XdmAuthKeyPtr) (data + 8);
442 break;
443 #ifdef XDMCP
444 case 8:
445 rho_bits = &global_rho;
446 key_bits = (XdmAuthKeyPtr) data;
447 break;
448 #endif
449 default:
450 return 0;
452 for (auth = xdmAuth; auth; auth = auth->next) {
453 if (XdmcpCompareKeys(rho_bits, &auth->rho) &&
454 XdmcpCompareKeys(key_bits, &auth->key)) {
455 xdmAuth = auth->next;
456 free(auth);
457 return 1;
460 return 0;
463 #endif