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#define XdmAuthenticationNameLen (sizeof XdmAuthenticationName - 1) 64static XdmAuthKeyRec rho; 65 66static Bool 67XdmAuthenticationValidator (ARRAY8Ptr privateData, ARRAY8Ptr incomingData, 68 xdmOpCode packet_type) 69{ 70 XdmAuthKeyPtr incoming; 71 72 XdmcpUnwrap (incomingData->data, (unsigned char *)&privateKey, 73 incomingData->data,incomingData->length); 74 if (packet_type == ACCEPT) { 75 if (incomingData->length != 8) 76 return FALSE; 77 incoming = (XdmAuthKeyPtr) incomingData->data; 78 XdmcpDecrementKey (incoming); 79 return XdmcpCompareKeys (incoming, &rho); 80 } 81 return FALSE; 82} 83 84static Bool 85XdmAuthenticationGenerator (ARRAY8Ptr privateData, ARRAY8Ptr outgoingData, 86 xdmOpCode packet_type) 87{ 88 outgoingData->length = 0; 89 outgoingData->data = 0; 90 if (packet_type == REQUEST) { 91 if (XdmcpAllocARRAY8 (outgoingData, 8)) 92 XdmcpWrap ((unsigned char *)&rho, (unsigned char *)&privateKey, 93 outgoingData->data, 8); 94 } 95 return TRUE; 96} 97 98static Bool 99XdmAuthenticationAddAuth (int name_len, const char *name, 100 int data_len, char *data) 101{ 102 Bool ret; 103 XdmcpUnwrap ((unsigned char *)data, (unsigned char *)&privateKey, 104 (unsigned char *)data, data_len); 105 authFromXDMCP = TRUE; 106 ret = AddAuthorization (name_len, name, data_len, data); 107 authFromXDMCP = FALSE; 108 return ret; 109} 110 111 112#define atox(c) ('0' <= c && c <= '9' ? c - '0' : \ 113 'a' <= c && c <= 'f' ? c - 'a' + 10 : \ 114 'A' <= c && c <= 'F' ? c - 'A' + 10 : -1) 115 116static int 117HexToBinary (const char *in, char *out, int len) 118{ 119 int top, bottom; 120 121 while (len > 0) 122 { 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 { 145 if (cookie_len > 2 + 2 * 8) 146 cookie_len = 2 + 2 * 8; 147 HexToBinary (cookie + 2, (char *)privateKey.data, cookie_len - 2); 148 } 149 else 150 { 151 if (cookie_len > 7) 152 cookie_len = 7; 153 memmove (privateKey.data + 1, cookie, cookie_len); 154 } 155 XdmcpGenerateKey (&rho); 156 XdmcpRegisterAuthentication (XdmAuthenticationName, XdmAuthenticationNameLen, 157 (char *)&rho, 158 sizeof (rho), 159 (ValidatorFunc)XdmAuthenticationValidator, 160 (GeneratorFunc)XdmAuthenticationGenerator, 161 (AddAuthorFunc)XdmAuthenticationAddAuth); 162} 163 164#endif /* XDMCP */ 165 166/* XDM-AUTHORIZATION-1 */ 167typedef struct _XdmAuthorization { 168 struct _XdmAuthorization *next; 169 XdmAuthKeyRec rho; 170 XdmAuthKeyRec key; 171 XID id; 172} XdmAuthorizationRec, *XdmAuthorizationPtr; 173 174static XdmAuthorizationPtr xdmAuth; 175 176typedef struct _XdmClientAuth { 177 struct _XdmClientAuth *next; 178 XdmAuthKeyRec rho; 179 char client[6]; 180 long time; 181} XdmClientAuthRec, *XdmClientAuthPtr; 182 183static XdmClientAuthPtr xdmClients; 184static long clockOffset; 185static Bool gotClock; 186 187#define TwentyMinutes (20 * 60) 188#define TwentyFiveMinutes (25 * 60) 189 190static Bool 191XdmClientAuthCompare (const XdmClientAuthPtr a, const XdmClientAuthPtr b) 192{ 193 int i; 194 195 if (!XdmcpCompareKeys (&a->rho, &b->rho)) 196 return FALSE; 197 for (i = 0; i < 6; i++) 198 if (a->client[i] != b->client[i]) 199 return FALSE; 200 return a->time == b->time; 201} 202 203static void 204XdmClientAuthDecode (const unsigned char *plain, XdmClientAuthPtr auth) 205{ 206 int i, j; 207 208 j = 0; 209 for (i = 0; i < 8; i++) 210 { 211 auth->rho.data[i] = plain[j]; 212 ++j; 213 } 214 for (i = 0; i < 6; i++) 215 { 216 auth->client[i] = plain[j]; 217 ++j; 218 } 219 auth->time = 0; 220 for (i = 0; i < 4; i++) 221 { 222 auth->time |= plain[j] << ((3 - i) << 3); 223 j++; 224 } 225} 226 227static void 228XdmClientAuthTimeout (long now) 229{ 230 XdmClientAuthPtr client, next, prev; 231 232 prev = 0; 233 for (client = xdmClients; client; client=next) 234 { 235 next = client->next; 236 if (abs (now - client->time) > TwentyFiveMinutes) 237 { 238 if (prev) 239 prev->next = next; 240 else 241 xdmClients = next; 242 free(client); 243 } 244 else 245 prev = client; 246 } 247} 248 249static XdmClientAuthPtr 250XdmAuthorizationValidate (unsigned char *plain, int length, 251 XdmAuthKeyPtr rho, ClientPtr xclient, char **reason) 252{ 253 XdmClientAuthPtr client, existing; 254 long now; 255 int i; 256 257 if (length != (192 / 8)) { 258 if (reason) 259 *reason = "Bad XDM authorization key length"; 260 return NULL; 261 } 262 client = malloc(sizeof (XdmClientAuthRec)); 263 if (!client) 264 return NULL; 265 XdmClientAuthDecode (plain, client); 266 if (!XdmcpCompareKeys (&client->rho, rho)) 267 { 268 free(client); 269 if (reason) 270 *reason = "Invalid XDM-AUTHORIZATION-1 key (failed key comparison)"; 271 return NULL; 272 } 273 for (i = 18; i < 24; i++) 274 if (plain[i] != 0) { 275 free(client); 276 if (reason) 277 *reason = "Invalid XDM-AUTHORIZATION-1 key (failed NULL check)"; 278 return NULL; 279 } 280 if (xclient) { 281 int family, addr_len; 282 Xtransaddr *addr; 283 284 if (_XSERVTransGetPeerAddr(((OsCommPtr)xclient->osPrivate)->trans_conn, 285 &family, &addr_len, &addr) == 0 286 && _XSERVTransConvertAddress(&family, &addr_len, &addr) == 0) { 287#if defined(TCPCONN) || defined(STREAMSCONN) 288 if (family == FamilyInternet && 289 memcmp((char *)addr, client->client, 4) != 0) { 290 free(client); 291 free(addr); 292 if (reason) 293 *reason = "Invalid XDM-AUTHORIZATION-1 key (failed address comparison)"; 294 return NULL; 295 296 } 297#endif 298 free(addr); 299 } 300 } 301 now = time(0); 302 if (!gotClock) 303 { 304 clockOffset = client->time - now; 305 gotClock = TRUE; 306 } 307 now += clockOffset; 308 XdmClientAuthTimeout (now); 309 if (abs (client->time - now) > TwentyMinutes) 310 { 311 free(client); 312 if (reason) 313 *reason = "Excessive XDM-AUTHORIZATION-1 time offset"; 314 return NULL; 315 } 316 for (existing = xdmClients; existing; existing=existing->next) 317 { 318 if (XdmClientAuthCompare (existing, client)) 319 { 320 free(client); 321 if (reason) 322 *reason = "XDM authorization key matches an existing client!"; 323 return NULL; 324 } 325 } 326 return client; 327} 328 329int 330XdmAddCookie (unsigned short data_length, const char *data, XID id) 331{ 332 XdmAuthorizationPtr new; 333 unsigned char *rho_bits, *key_bits; 334 335 switch (data_length) 336 { 337 case 16: /* auth from files is 16 bytes long */ 338#ifdef XDMCP 339 if (authFromXDMCP) 340 { 341 /* R5 xdm sent bogus authorization data in the accept packet, 342 * but we can recover */ 343 rho_bits = rho.data; 344 key_bits = (unsigned char *) data; 345 key_bits[0] = '\0'; 346 } 347 else 348#endif 349 { 350 rho_bits = (unsigned char *) data; 351 key_bits = (unsigned char *) (data + 8); 352 } 353 break; 354#ifdef XDMCP 355 case 8: /* auth from XDMCP is 8 bytes long */ 356 rho_bits = rho.data; 357 key_bits = (unsigned char *) data; 358 break; 359#endif 360 default: 361 return 0; 362 } 363 /* the first octet of the key must be zero */ 364 if (key_bits[0] != '\0') 365 return 0; 366 new = malloc(sizeof (XdmAuthorizationRec)); 367 if (!new) 368 return 0; 369 new->next = xdmAuth; 370 xdmAuth = new; 371 memmove (new->key.data, key_bits, (int) 8); 372 memmove (new->rho.data, rho_bits, (int) 8); 373 new->id = id; 374 return 1; 375} 376 377XID 378XdmCheckCookie (unsigned short cookie_length, const char *cookie, 379 ClientPtr xclient, char **reason) 380{ 381 XdmAuthorizationPtr auth; 382 XdmClientAuthPtr client; 383 unsigned char *plain; 384 385 /* Auth packets must be a multiple of 8 bytes long */ 386 if (cookie_length & 7) 387 return (XID) -1; 388 plain = malloc(cookie_length); 389 if (!plain) 390 return (XID) -1; 391 for (auth = xdmAuth; auth; auth=auth->next) { 392 XdmcpUnwrap ((unsigned char *)cookie, (unsigned char *)&auth->key, plain, cookie_length); 393 if ((client = XdmAuthorizationValidate (plain, cookie_length, &auth->rho, xclient, reason)) != NULL) 394 { 395 client->next = xdmClients; 396 xdmClients = client; 397 free(plain); 398 return auth->id; 399 } 400 } 401 free(plain); 402 return (XID) -1; 403} 404 405int 406XdmResetCookie (void) 407{ 408 XdmAuthorizationPtr auth, next_auth; 409 XdmClientAuthPtr client, next_client; 410 411 for (auth = xdmAuth; auth; auth=next_auth) 412 { 413 next_auth = auth->next; 414 free(auth); 415 } 416 xdmAuth = 0; 417 for (client = xdmClients; client; client=next_client) 418 { 419 next_client = client->next; 420 free(client); 421 } 422 xdmClients = (XdmClientAuthPtr) 0; 423 return 1; 424} 425 426int 427XdmFromID (XID id, unsigned short *data_lenp, char **datap) 428{ 429 XdmAuthorizationPtr auth; 430 431 for (auth = xdmAuth; auth; auth=auth->next) { 432 if (id == auth->id) { 433 *data_lenp = 16; 434 *datap = (char *) &auth->rho; 435 return 1; 436 } 437 } 438 return 0; 439} 440 441int 442XdmRemoveCookie (unsigned short data_length, const char *data) 443{ 444 XdmAuthorizationPtr auth; 445 XdmAuthKeyPtr key_bits, rho_bits; 446 447 switch (data_length) 448 { 449 case 16: 450 rho_bits = (XdmAuthKeyPtr) data; 451 key_bits = (XdmAuthKeyPtr) (data + 8); 452 break; 453#ifdef XDMCP 454 case 8: 455 rho_bits = ρ 456 key_bits = (XdmAuthKeyPtr) data; 457 break; 458#endif 459 default: 460 return 0; 461 } 462 for (auth = xdmAuth; auth; auth=auth->next) { 463 if (XdmcpCompareKeys (rho_bits, &auth->rho) && 464 XdmcpCompareKeys (key_bits, &auth->key)) 465 { 466 xdmAuth = auth->next; 467 free(auth); 468 return 1; 469 } 470 } 471 return 0; 472} 473 474#endif 475