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 global_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, &global_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 *) &global_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(&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 */ 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 (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 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) 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 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 = 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 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 414int 415XdmFromID(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 429int 430XdmRemoveCookie(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