security.c revision 05b261ec
1/* 2 3Copyright 1996, 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 in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from The Open Group. 24 25*/ 26 27#ifdef HAVE_DIX_CONFIG_H 28#include <dix-config.h> 29#endif 30 31#include "dixstruct.h" 32#include "extnsionst.h" 33#include "windowstr.h" 34#include "inputstr.h" 35#include "scrnintstr.h" 36#include "gcstruct.h" 37#include "colormapst.h" 38#include "propertyst.h" 39#include "xacestr.h" 40#include "securitysrv.h" 41#include <X11/extensions/securstr.h> 42#include <assert.h> 43#include <stdarg.h> 44#ifdef XAPPGROUP 45#include "appgroup.h" 46#endif 47#include <stdio.h> /* for file reading operations */ 48#include <X11/Xatom.h> /* for XA_STRING */ 49 50#ifndef DEFAULTPOLICYFILE 51# define DEFAULTPOLICYFILE NULL 52#endif 53#if defined(WIN32) || defined(__CYGWIN__) 54#include <X11/Xos.h> 55#undef index 56#endif 57 58#include "modinit.h" 59 60static int SecurityErrorBase; /* first Security error number */ 61static int SecurityEventBase; /* first Security event number */ 62static int securityClientPrivateIndex; 63static int securityExtnsnPrivateIndex; 64 65/* this is what we store as client security state */ 66typedef struct { 67 unsigned int trustLevel; 68 XID authId; 69} SecurityClientStateRec; 70 71#define STATEVAL(extnsn) \ 72 ((extnsn)->devPrivates[securityExtnsnPrivateIndex].val) 73#define STATEPTR(client) \ 74 ((client)->devPrivates[securityClientPrivateIndex].ptr) 75#define TRUSTLEVEL(client) \ 76 (((SecurityClientStateRec*)STATEPTR(client))->trustLevel) 77#define AUTHID(client) \ 78 (((SecurityClientStateRec*)STATEPTR(client))->authId) 79 80static CallbackListPtr SecurityValidateGroupCallback = NULL; 81 82RESTYPE SecurityAuthorizationResType; /* resource type for authorizations */ 83 84static RESTYPE RTEventClient; 85 86#define CALLBACK(name) static void \ 87name(CallbackListPtr *pcbl, pointer nulldata, pointer calldata) 88 89/* SecurityAudit 90 * 91 * Arguments: 92 * format is the formatting string to be used to interpret the 93 * remaining arguments. 94 * 95 * Returns: nothing. 96 * 97 * Side Effects: 98 * Writes the message to the log file if security logging is on. 99 */ 100 101static void 102SecurityAudit(char *format, ...) 103{ 104 va_list args; 105 106 if (auditTrailLevel < SECURITY_AUDIT_LEVEL) 107 return; 108 va_start(args, format); 109 VAuditF(format, args); 110 va_end(args); 111} /* SecurityAudit */ 112 113#define rClient(obj) (clients[CLIENT_ID((obj)->resource)]) 114 115/* SecurityDeleteAuthorization 116 * 117 * Arguments: 118 * value is the authorization to delete. 119 * id is its resource ID. 120 * 121 * Returns: Success. 122 * 123 * Side Effects: 124 * Frees everything associated with the authorization. 125 */ 126 127static int 128SecurityDeleteAuthorization( 129 pointer value, 130 XID id) 131{ 132 SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)value; 133 unsigned short name_len, data_len; 134 char *name, *data; 135 int status; 136 int i; 137 OtherClientsPtr pEventClient; 138 139 /* Remove the auth using the os layer auth manager */ 140 141 status = AuthorizationFromID(pAuth->id, &name_len, &name, 142 &data_len, &data); 143 assert(status); 144 status = RemoveAuthorization(name_len, name, data_len, data); 145 assert(status); 146 (void)status; 147 148 /* free the auth timer if there is one */ 149 150 if (pAuth->timer) TimerFree(pAuth->timer); 151 152 /* send revoke events */ 153 154 while ((pEventClient = pAuth->eventClients)) 155 { 156 /* send revocation event event */ 157 ClientPtr client = rClient(pEventClient); 158 159 if (!client->clientGone) 160 { 161 xSecurityAuthorizationRevokedEvent are; 162 are.type = SecurityEventBase + XSecurityAuthorizationRevoked; 163 are.sequenceNumber = client->sequence; 164 are.authId = pAuth->id; 165 WriteEventsToClient(client, 1, (xEvent *)&are); 166 } 167 FreeResource(pEventClient->resource, RT_NONE); 168 } 169 170 /* kill all clients using this auth */ 171 172 for (i = 1; i<currentMaxClients; i++) 173 { 174 if (clients[i] && (AUTHID(clients[i]) == pAuth->id)) 175 CloseDownClient(clients[i]); 176 } 177 178 SecurityAudit("revoked authorization ID %d\n", pAuth->id); 179 xfree(pAuth); 180 return Success; 181 182} /* SecurityDeleteAuthorization */ 183 184 185/* resource delete function for RTEventClient */ 186static int 187SecurityDeleteAuthorizationEventClient( 188 pointer value, 189 XID id) 190{ 191 OtherClientsPtr pEventClient, prev = NULL; 192 SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)value; 193 194 for (pEventClient = pAuth->eventClients; 195 pEventClient; 196 pEventClient = pEventClient->next) 197 { 198 if (pEventClient->resource == id) 199 { 200 if (prev) 201 prev->next = pEventClient->next; 202 else 203 pAuth->eventClients = pEventClient->next; 204 xfree(pEventClient); 205 return(Success); 206 } 207 prev = pEventClient; 208 } 209 /*NOTREACHED*/ 210 return -1; /* make compiler happy */ 211} /* SecurityDeleteAuthorizationEventClient */ 212 213 214/* SecurityComputeAuthorizationTimeout 215 * 216 * Arguments: 217 * pAuth is the authorization for which we are computing the timeout 218 * seconds is the number of seconds we want to wait 219 * 220 * Returns: 221 * the number of milliseconds that the auth timer should be set to 222 * 223 * Side Effects: 224 * Sets pAuth->secondsRemaining to any "overflow" amount of time 225 * that didn't fit in 32 bits worth of milliseconds 226 */ 227 228static CARD32 229SecurityComputeAuthorizationTimeout( 230 SecurityAuthorizationPtr pAuth, 231 unsigned int seconds) 232{ 233 /* maxSecs is the number of full seconds that can be expressed in 234 * 32 bits worth of milliseconds 235 */ 236 CARD32 maxSecs = (CARD32)(~0) / (CARD32)MILLI_PER_SECOND; 237 238 if (seconds > maxSecs) 239 { /* only come here if we want to wait more than 49 days */ 240 pAuth->secondsRemaining = seconds - maxSecs; 241 return maxSecs * MILLI_PER_SECOND; 242 } 243 else 244 { /* by far the common case */ 245 pAuth->secondsRemaining = 0; 246 return seconds * MILLI_PER_SECOND; 247 } 248} /* SecurityStartAuthorizationTimer */ 249 250/* SecurityAuthorizationExpired 251 * 252 * This function is passed as an argument to TimerSet and gets called from 253 * the timer manager in the os layer when its time is up. 254 * 255 * Arguments: 256 * timer is the timer for this authorization. 257 * time is the current time. 258 * pval is the authorization whose time is up. 259 * 260 * Returns: 261 * A new time delay in milliseconds if the timer should wait some 262 * more, else zero. 263 * 264 * Side Effects: 265 * Frees the authorization resource if the timeout period is really 266 * over, otherwise recomputes pAuth->secondsRemaining. 267 */ 268 269static CARD32 270SecurityAuthorizationExpired( 271 OsTimerPtr timer, 272 CARD32 time, 273 pointer pval) 274{ 275 SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)pval; 276 277 assert(pAuth->timer == timer); 278 279 if (pAuth->secondsRemaining) 280 { 281 return SecurityComputeAuthorizationTimeout(pAuth, 282 pAuth->secondsRemaining); 283 } 284 else 285 { 286 FreeResource(pAuth->id, RT_NONE); 287 return 0; 288 } 289} /* SecurityAuthorizationExpired */ 290 291/* SecurityStartAuthorizationTimer 292 * 293 * Arguments: 294 * pAuth is the authorization whose timer should be started. 295 * 296 * Returns: nothing. 297 * 298 * Side Effects: 299 * A timer is started, set to expire after the timeout period for 300 * this authorization. When it expires, the function 301 * SecurityAuthorizationExpired will be called. 302 */ 303 304static void 305SecurityStartAuthorizationTimer( 306 SecurityAuthorizationPtr pAuth) 307{ 308 pAuth->timer = TimerSet(pAuth->timer, 0, 309 SecurityComputeAuthorizationTimeout(pAuth, pAuth->timeout), 310 SecurityAuthorizationExpired, pAuth); 311} /* SecurityStartAuthorizationTimer */ 312 313 314/* Proc functions all take a client argument, execute the request in 315 * client->requestBuffer, and return a protocol error status. 316 */ 317 318static int 319ProcSecurityQueryVersion( 320 ClientPtr client) 321{ 322 /* REQUEST(xSecurityQueryVersionReq); */ 323 xSecurityQueryVersionReply rep; 324 325 /* paranoia: this "can't happen" because this extension is hidden 326 * from untrusted clients, but just in case... 327 */ 328 if (TRUSTLEVEL(client) != XSecurityClientTrusted) 329 return BadRequest; 330 331 REQUEST_SIZE_MATCH(xSecurityQueryVersionReq); 332 rep.type = X_Reply; 333 rep.sequenceNumber = client->sequence; 334 rep.length = 0; 335 rep.majorVersion = SECURITY_MAJOR_VERSION; 336 rep.minorVersion = SECURITY_MINOR_VERSION; 337 if(client->swapped) 338 { 339 register char n; 340 swaps(&rep.sequenceNumber, n); 341 swaps(&rep.majorVersion, n); 342 swaps(&rep.minorVersion, n); 343 } 344 (void)WriteToClient(client, SIZEOF(xSecurityQueryVersionReply), 345 (char *)&rep); 346 return (client->noClientException); 347} /* ProcSecurityQueryVersion */ 348 349 350static int 351SecurityEventSelectForAuthorization( 352 SecurityAuthorizationPtr pAuth, 353 ClientPtr client, 354 Mask mask) 355{ 356 OtherClients *pEventClient; 357 358 for (pEventClient = pAuth->eventClients; 359 pEventClient; 360 pEventClient = pEventClient->next) 361 { 362 if (SameClient(pEventClient, client)) 363 { 364 if (mask == 0) 365 FreeResource(pEventClient->resource, RT_NONE); 366 else 367 pEventClient->mask = mask; 368 return Success; 369 } 370 } 371 372 pEventClient = (OtherClients *) xalloc(sizeof(OtherClients)); 373 if (!pEventClient) 374 return BadAlloc; 375 pEventClient->mask = mask; 376 pEventClient->resource = FakeClientID(client->index); 377 pEventClient->next = pAuth->eventClients; 378 if (!AddResource(pEventClient->resource, RTEventClient, 379 (pointer)pAuth)) 380 { 381 xfree(pEventClient); 382 return BadAlloc; 383 } 384 pAuth->eventClients = pEventClient; 385 386 return Success; 387} /* SecurityEventSelectForAuthorization */ 388 389 390static int 391ProcSecurityGenerateAuthorization( 392 ClientPtr client) 393{ 394 REQUEST(xSecurityGenerateAuthorizationReq); 395 int len; /* request length in CARD32s*/ 396 Bool removeAuth = FALSE; /* if bailout, call RemoveAuthorization? */ 397 SecurityAuthorizationPtr pAuth = NULL; /* auth we are creating */ 398 int err; /* error to return from this function */ 399 XID authId; /* authorization ID assigned by os layer */ 400 xSecurityGenerateAuthorizationReply rep; /* reply struct */ 401 unsigned int trustLevel; /* trust level of new auth */ 402 XID group; /* group of new auth */ 403 CARD32 timeout; /* timeout of new auth */ 404 CARD32 *values; /* list of supplied attributes */ 405 char *protoname; /* auth proto name sent in request */ 406 char *protodata; /* auth proto data sent in request */ 407 unsigned int authdata_len; /* # bytes of generated auth data */ 408 char *pAuthdata; /* generated auth data */ 409 Mask eventMask; /* what events on this auth does client want */ 410 411 /* paranoia: this "can't happen" because this extension is hidden 412 * from untrusted clients, but just in case... 413 */ 414 if (TRUSTLEVEL(client) != XSecurityClientTrusted) 415 return BadRequest; 416 417 /* check request length */ 418 419 REQUEST_AT_LEAST_SIZE(xSecurityGenerateAuthorizationReq); 420 len = SIZEOF(xSecurityGenerateAuthorizationReq) >> 2; 421 len += (stuff->nbytesAuthProto + (unsigned)3) >> 2; 422 len += (stuff->nbytesAuthData + (unsigned)3) >> 2; 423 values = ((CARD32 *)stuff) + len; 424 len += Ones(stuff->valueMask); 425 if (client->req_len != len) 426 return BadLength; 427 428 /* check valuemask */ 429 if (stuff->valueMask & ~XSecurityAllAuthorizationAttributes) 430 { 431 client->errorValue = stuff->valueMask; 432 return BadValue; 433 } 434 435 /* check timeout */ 436 timeout = 60; 437 if (stuff->valueMask & XSecurityTimeout) 438 { 439 timeout = *values++; 440 } 441 442 /* check trustLevel */ 443 trustLevel = XSecurityClientUntrusted; 444 if (stuff->valueMask & XSecurityTrustLevel) 445 { 446 trustLevel = *values++; 447 if (trustLevel != XSecurityClientTrusted && 448 trustLevel != XSecurityClientUntrusted) 449 { 450 client->errorValue = trustLevel; 451 return BadValue; 452 } 453 } 454 455 /* check group */ 456 group = None; 457 if (stuff->valueMask & XSecurityGroup) 458 { 459 group = *values++; 460 if (SecurityValidateGroupCallback) 461 { 462 SecurityValidateGroupInfoRec vgi; 463 vgi.group = group; 464 vgi.valid = FALSE; 465 CallCallbacks(&SecurityValidateGroupCallback, (pointer)&vgi); 466 467 /* if nobody said they recognized it, it's an error */ 468 469 if (!vgi.valid) 470 { 471 client->errorValue = group; 472 return BadValue; 473 } 474 } 475 } 476 477 /* check event mask */ 478 eventMask = 0; 479 if (stuff->valueMask & XSecurityEventMask) 480 { 481 eventMask = *values++; 482 if (eventMask & ~XSecurityAllEventMasks) 483 { 484 client->errorValue = eventMask; 485 return BadValue; 486 } 487 } 488 489 protoname = (char *)&stuff[1]; 490 protodata = protoname + ((stuff->nbytesAuthProto + (unsigned)3) >> 2); 491 492 /* call os layer to generate the authorization */ 493 494 authId = GenerateAuthorization(stuff->nbytesAuthProto, protoname, 495 stuff->nbytesAuthData, protodata, 496 &authdata_len, &pAuthdata); 497 if ((XID) ~0L == authId) 498 { 499 err = SecurityErrorBase + XSecurityBadAuthorizationProtocol; 500 goto bailout; 501 } 502 503 /* now that we've added the auth, remember to remove it if we have to 504 * abort the request for some reason (like allocation failure) 505 */ 506 removeAuth = TRUE; 507 508 /* associate additional information with this auth ID */ 509 510 pAuth = (SecurityAuthorizationPtr)xalloc(sizeof(SecurityAuthorizationRec)); 511 if (!pAuth) 512 { 513 err = BadAlloc; 514 goto bailout; 515 } 516 517 /* fill in the auth fields */ 518 519 pAuth->id = authId; 520 pAuth->timeout = timeout; 521 pAuth->group = group; 522 pAuth->trustLevel = trustLevel; 523 pAuth->refcnt = 0; /* the auth was just created; nobody's using it yet */ 524 pAuth->secondsRemaining = 0; 525 pAuth->timer = NULL; 526 pAuth->eventClients = NULL; 527 528 /* handle event selection */ 529 if (eventMask) 530 { 531 err = SecurityEventSelectForAuthorization(pAuth, client, eventMask); 532 if (err != Success) 533 goto bailout; 534 } 535 536 if (!AddResource(authId, SecurityAuthorizationResType, pAuth)) 537 { 538 err = BadAlloc; 539 goto bailout; 540 } 541 542 /* start the timer ticking */ 543 544 if (pAuth->timeout != 0) 545 SecurityStartAuthorizationTimer(pAuth); 546 547 /* tell client the auth id and data */ 548 549 rep.type = X_Reply; 550 rep.length = (authdata_len + 3) >> 2; 551 rep.sequenceNumber = client->sequence; 552 rep.authId = authId; 553 rep.dataLength = authdata_len; 554 555 if (client->swapped) 556 { 557 register char n; 558 swapl(&rep.length, n); 559 swaps(&rep.sequenceNumber, n); 560 swapl(&rep.authId, n); 561 swaps(&rep.dataLength, n); 562 } 563 564 WriteToClient(client, SIZEOF(xSecurityGenerateAuthorizationReply), 565 (char *)&rep); 566 WriteToClient(client, authdata_len, pAuthdata); 567 568 SecurityAudit("client %d generated authorization %d trust %d timeout %d group %d events %d\n", 569 client->index, pAuth->id, pAuth->trustLevel, pAuth->timeout, 570 pAuth->group, eventMask); 571 572 /* the request succeeded; don't call RemoveAuthorization or free pAuth */ 573 574 removeAuth = FALSE; 575 pAuth = NULL; 576 err = client->noClientException; 577 578bailout: 579 if (removeAuth) 580 RemoveAuthorization(stuff->nbytesAuthProto, protoname, 581 authdata_len, pAuthdata); 582 if (pAuth) xfree(pAuth); 583 return err; 584 585} /* ProcSecurityGenerateAuthorization */ 586 587static int 588ProcSecurityRevokeAuthorization( 589 ClientPtr client) 590{ 591 REQUEST(xSecurityRevokeAuthorizationReq); 592 SecurityAuthorizationPtr pAuth; 593 594 /* paranoia: this "can't happen" because this extension is hidden 595 * from untrusted clients, but just in case... 596 */ 597 if (TRUSTLEVEL(client) != XSecurityClientTrusted) 598 return BadRequest; 599 600 REQUEST_SIZE_MATCH(xSecurityRevokeAuthorizationReq); 601 602 pAuth = (SecurityAuthorizationPtr)SecurityLookupIDByType(client, 603 stuff->authId, SecurityAuthorizationResType, DixDestroyAccess); 604 if (!pAuth) 605 return SecurityErrorBase + XSecurityBadAuthorization; 606 607 FreeResource(stuff->authId, RT_NONE); 608 return Success; 609} /* ProcSecurityRevokeAuthorization */ 610 611 612static int 613ProcSecurityDispatch( 614 ClientPtr client) 615{ 616 REQUEST(xReq); 617 618 switch (stuff->data) 619 { 620 case X_SecurityQueryVersion: 621 return ProcSecurityQueryVersion(client); 622 case X_SecurityGenerateAuthorization: 623 return ProcSecurityGenerateAuthorization(client); 624 case X_SecurityRevokeAuthorization: 625 return ProcSecurityRevokeAuthorization(client); 626 default: 627 return BadRequest; 628 } 629} /* ProcSecurityDispatch */ 630 631static int 632SProcSecurityQueryVersion( 633 ClientPtr client) 634{ 635 REQUEST(xSecurityQueryVersionReq); 636 register char n; 637 638 swaps(&stuff->length, n); 639 REQUEST_SIZE_MATCH(xSecurityQueryVersionReq); 640 swaps(&stuff->majorVersion, n); 641 swaps(&stuff->minorVersion,n); 642 return ProcSecurityQueryVersion(client); 643} /* SProcSecurityQueryVersion */ 644 645 646static int 647SProcSecurityGenerateAuthorization( 648 ClientPtr client) 649{ 650 REQUEST(xSecurityGenerateAuthorizationReq); 651 register char n; 652 CARD32 *values; 653 unsigned long nvalues; 654 int values_offset; 655 656 swaps(&stuff->length, n); 657 REQUEST_AT_LEAST_SIZE(xSecurityGenerateAuthorizationReq); 658 swaps(&stuff->nbytesAuthProto, n); 659 swaps(&stuff->nbytesAuthData, n); 660 swapl(&stuff->valueMask, n); 661 values_offset = ((stuff->nbytesAuthProto + (unsigned)3) >> 2) + 662 ((stuff->nbytesAuthData + (unsigned)3) >> 2); 663 if (values_offset > 664 stuff->length - (sz_xSecurityGenerateAuthorizationReq >> 2)) 665 return BadLength; 666 values = (CARD32 *)(&stuff[1]) + values_offset; 667 nvalues = (((CARD32 *)stuff) + stuff->length) - values; 668 SwapLongs(values, nvalues); 669 return ProcSecurityGenerateAuthorization(client); 670} /* SProcSecurityGenerateAuthorization */ 671 672 673static int 674SProcSecurityRevokeAuthorization( 675 ClientPtr client) 676{ 677 REQUEST(xSecurityRevokeAuthorizationReq); 678 register char n; 679 680 swaps(&stuff->length, n); 681 REQUEST_SIZE_MATCH(xSecurityRevokeAuthorizationReq); 682 swapl(&stuff->authId, n); 683 return ProcSecurityRevokeAuthorization(client); 684} /* SProcSecurityRevokeAuthorization */ 685 686 687static int 688SProcSecurityDispatch( 689 ClientPtr client) 690{ 691 REQUEST(xReq); 692 693 switch (stuff->data) 694 { 695 case X_SecurityQueryVersion: 696 return SProcSecurityQueryVersion(client); 697 case X_SecurityGenerateAuthorization: 698 return SProcSecurityGenerateAuthorization(client); 699 case X_SecurityRevokeAuthorization: 700 return SProcSecurityRevokeAuthorization(client); 701 default: 702 return BadRequest; 703 } 704} /* SProcSecurityDispatch */ 705 706static void 707SwapSecurityAuthorizationRevokedEvent( 708 xSecurityAuthorizationRevokedEvent *from, 709 xSecurityAuthorizationRevokedEvent *to) 710{ 711 to->type = from->type; 712 to->detail = from->detail; 713 cpswaps(from->sequenceNumber, to->sequenceNumber); 714 cpswapl(from->authId, to->authId); 715} 716 717/* SecurityDetermineEventPropogationLimits 718 * 719 * This is a helper function for SecurityCheckDeviceAccess. 720 * 721 * Arguments: 722 * dev is the device for which the starting and stopping windows for 723 * event propogation should be determined. 724 * The values pointed to by ppWin and ppStopWin are not used. 725 * 726 * Returns: 727 * ppWin is filled in with a pointer to the window at which event 728 * propogation for the given device should start given the current 729 * state of the server (pointer position, window layout, etc.) 730 * ppStopWin is filled in with the window at which event propogation 731 * should stop; events should not go to ppStopWin. 732 * 733 * Side Effects: none. 734 */ 735 736static void 737SecurityDetermineEventPropogationLimits( 738 DeviceIntPtr dev, 739 WindowPtr *ppWin, 740 WindowPtr *ppStopWin) 741{ 742 WindowPtr pFocusWin = dev->focus ? dev->focus->win : NoneWin; 743 744 if (pFocusWin == NoneWin) 745 { /* no focus -- events don't go anywhere */ 746 *ppWin = *ppStopWin = NULL; 747 return; 748 } 749 750 if (pFocusWin == PointerRootWin) 751 { /* focus follows the pointer */ 752 *ppWin = GetSpriteWindow(); 753 *ppStopWin = NULL; /* propogate all the way to the root */ 754 } 755 else 756 { /* a real window is set for the focus */ 757 WindowPtr pSpriteWin = GetSpriteWindow(); 758 *ppStopWin = pFocusWin->parent; /* don't go past the focus window */ 759 760 /* if the pointer is in a subwindow of the focus window, start 761 * at that subwindow, else start at the focus window itself 762 */ 763 if (IsParent(pFocusWin, pSpriteWin)) 764 *ppWin = pSpriteWin; 765 else *ppWin = pFocusWin; 766 } 767} /* SecurityDetermineEventPropogationLimits */ 768 769 770/* SecurityCheckDeviceAccess 771 * 772 * Arguments: 773 * client is the client attempting to access a device. 774 * dev is the device being accessed. 775 * fromRequest is TRUE if the device access is a direct result of 776 * the client executing some request and FALSE if it is a 777 * result of the server trying to send an event (e.g. KeymapNotify) 778 * to the client. 779 * Returns: 780 * TRUE if the device access should be allowed, else FALSE. 781 * 782 * Side Effects: 783 * An audit message is generated if access is denied. 784 */ 785 786CALLBACK(SecurityCheckDeviceAccess) 787{ 788 XaceDeviceAccessRec *rec = (XaceDeviceAccessRec*)calldata; 789 ClientPtr client = rec->client; 790 DeviceIntPtr dev = rec->dev; 791 Bool fromRequest = rec->fromRequest; 792 WindowPtr pWin, pStopWin; 793 Bool untrusted_got_event; 794 Bool found_event_window; 795 Mask eventmask; 796 int reqtype = 0; 797 798 /* trusted clients always allowed to do anything */ 799 if (TRUSTLEVEL(client) == XSecurityClientTrusted) 800 return; 801 802 /* device security other than keyboard is not implemented yet */ 803 if (dev != inputInfo.keyboard) 804 return; 805 806 /* some untrusted client wants access */ 807 808 if (fromRequest) 809 { 810 reqtype = ((xReq *)client->requestBuffer)->reqType; 811 switch (reqtype) 812 { 813 /* never allow these */ 814 case X_ChangeKeyboardMapping: 815 case X_ChangeKeyboardControl: 816 case X_SetModifierMapping: 817 SecurityAudit("client %d attempted request %d\n", 818 client->index, reqtype); 819 rec->rval = FALSE; 820 return; 821 default: 822 break; 823 } 824 } 825 826 untrusted_got_event = FALSE; 827 found_event_window = FALSE; 828 829 if (dev->grab) 830 { 831 untrusted_got_event = 832 (TRUSTLEVEL(rClient(dev->grab)) != XSecurityClientTrusted); 833 } 834 else 835 { 836 SecurityDetermineEventPropogationLimits(dev, &pWin, &pStopWin); 837 838 eventmask = KeyPressMask | KeyReleaseMask; 839 while ( (pWin != pStopWin) && !found_event_window) 840 { 841 OtherClients *other; 842 843 if (pWin->eventMask & eventmask) 844 { 845 found_event_window = TRUE; 846 client = wClient(pWin); 847 if (TRUSTLEVEL(client) != XSecurityClientTrusted) 848 { 849 untrusted_got_event = TRUE; 850 } 851 } 852 if (wOtherEventMasks(pWin) & eventmask) 853 { 854 found_event_window = TRUE; 855 for (other = wOtherClients(pWin); other; other = other->next) 856 { 857 if (other->mask & eventmask) 858 { 859 client = rClient(other); 860 if (TRUSTLEVEL(client) != XSecurityClientTrusted) 861 { 862 untrusted_got_event = TRUE; 863 break; 864 } 865 } 866 } 867 } 868 if (wDontPropagateMask(pWin) & eventmask) 869 break; 870 pWin = pWin->parent; 871 } /* while propogating the event */ 872 } 873 874 /* allow access by untrusted clients only if an event would have gone 875 * to an untrusted client 876 */ 877 878 if (!untrusted_got_event) 879 { 880 char *devname = dev->name; 881 if (!devname) devname = "unnamed"; 882 if (fromRequest) 883 SecurityAudit("client %d attempted request %d device %d (%s)\n", 884 client->index, reqtype, dev->id, devname); 885 else 886 SecurityAudit("client %d attempted to access device %d (%s)\n", 887 client->index, dev->id, devname); 888 rec->rval = FALSE; 889 } 890 return; 891} /* SecurityCheckDeviceAccess */ 892 893 894 895/* SecurityAuditResourceIDAccess 896 * 897 * Arguments: 898 * client is the client doing the resource access. 899 * id is the resource id. 900 * 901 * Returns: NULL 902 * 903 * Side Effects: 904 * An audit message is generated with details of the denied 905 * resource access. 906 */ 907 908static pointer 909SecurityAuditResourceIDAccess( 910 ClientPtr client, 911 XID id) 912{ 913 int cid = CLIENT_ID(id); 914 int reqtype = ((xReq *)client->requestBuffer)->reqType; 915 switch (reqtype) 916 { 917 case X_ChangeProperty: 918 case X_DeleteProperty: 919 case X_GetProperty: 920 { 921 xChangePropertyReq *req = 922 (xChangePropertyReq *)client->requestBuffer; 923 int propertyatom = req->property; 924 char *propertyname = NameForAtom(propertyatom); 925 926 SecurityAudit("client %d attempted request %d with window 0x%x property %s of client %d\n", 927 client->index, reqtype, id, propertyname, cid); 928 break; 929 } 930 default: 931 { 932 SecurityAudit("client %d attempted request %d with resource 0x%x of client %d\n", 933 client->index, reqtype, id, cid); 934 break; 935 } 936 } 937 return NULL; 938} /* SecurityAuditResourceIDAccess */ 939 940 941/* SecurityCheckResourceIDAccess 942 * 943 * This function gets plugged into client->CheckAccess and is called from 944 * SecurityLookupIDByType/Class to determine if the client can access the 945 * resource. 946 * 947 * Arguments: 948 * client is the client doing the resource access. 949 * id is the resource id. 950 * rtype is its type or class. 951 * access_mode represents the intended use of the resource; see 952 * resource.h. 953 * res is a pointer to the resource structure for this resource. 954 * 955 * Returns: 956 * If access is granted, the value of rval that was passed in, else FALSE. 957 * 958 * Side Effects: 959 * Disallowed resource accesses are audited. 960 */ 961 962CALLBACK(SecurityCheckResourceIDAccess) 963{ 964 XaceResourceAccessRec *rec = (XaceResourceAccessRec*)calldata; 965 ClientPtr client = rec->client; 966 XID id = rec->id; 967 RESTYPE rtype = rec->rtype; 968 Mask access_mode = rec->access_mode; 969 pointer rval = rec->res; 970 int cid, reqtype; 971 972 if (TRUSTLEVEL(client) == XSecurityClientTrusted || 973 DixUnknownAccess == access_mode) 974 return; /* for compatibility, we have to allow access */ 975 976 cid = CLIENT_ID(id); 977 reqtype = ((xReq *)client->requestBuffer)->reqType; 978 switch (reqtype) 979 { /* these are always allowed */ 980 case X_QueryTree: 981 case X_TranslateCoords: 982 case X_GetGeometry: 983 /* property access is controlled in SecurityCheckPropertyAccess */ 984 case X_GetProperty: 985 case X_ChangeProperty: 986 case X_DeleteProperty: 987 case X_RotateProperties: 988 case X_ListProperties: 989 return; 990 default: 991 break; 992 } 993 994 if (cid != 0) 995 { /* not a server-owned resource */ 996 /* 997 * The following 'if' restricts clients to only access resources at 998 * the same trustLevel. Since there are currently only two trust levels, 999 * and trusted clients never call this function, this degenerates into 1000 * saying that untrusted clients can only access resources of other 1001 * untrusted clients. One way to add the notion of groups would be to 1002 * allow values other than Trusted (0) and Untrusted (1) for this field. 1003 * Clients at the same trust level would be able to use each other's 1004 * resources, but not those of clients at other trust levels. I haven't 1005 * tried it, but this probably mostly works already. The obvious 1006 * competing alternative for grouping clients for security purposes is to 1007 * use app groups. dpw 1008 */ 1009 if (TRUSTLEVEL(client) == TRUSTLEVEL(clients[cid]) 1010#ifdef XAPPGROUP 1011 || (RT_COLORMAP == rtype && 1012 XagDefaultColormap (client) == (Colormap) id) 1013#endif 1014 ) 1015 return; 1016 else 1017 goto deny; 1018 } 1019 else /* server-owned resource - probably a default colormap or root window */ 1020 { 1021 if (RC_DRAWABLE & rtype) 1022 { 1023 switch (reqtype) 1024 { /* the following operations are allowed on root windows */ 1025 case X_CreatePixmap: 1026 case X_CreateGC: 1027 case X_CreateWindow: 1028 case X_CreateColormap: 1029 case X_ListProperties: 1030 case X_GrabPointer: 1031 case X_UngrabButton: 1032 case X_QueryBestSize: 1033 case X_GetWindowAttributes: 1034 break; 1035 case X_SendEvent: 1036 { /* see if it is an event specified by the ICCCM */ 1037 xSendEventReq *req = (xSendEventReq *) 1038 (client->requestBuffer); 1039 if (req->propagate == xTrue 1040 || 1041 (req->eventMask != ColormapChangeMask && 1042 req->eventMask != StructureNotifyMask && 1043 req->eventMask != 1044 (SubstructureRedirectMask|SubstructureNotifyMask) 1045 ) 1046 || 1047 (req->event.u.u.type != UnmapNotify && 1048 req->event.u.u.type != ConfigureRequest && 1049 req->event.u.u.type != ClientMessage 1050 ) 1051 ) 1052 { /* not an ICCCM event */ 1053 goto deny; 1054 } 1055 break; 1056 } /* case X_SendEvent on root */ 1057 1058 case X_ChangeWindowAttributes: 1059 { /* Allow selection of PropertyNotify and StructureNotify 1060 * events on the root. 1061 */ 1062 xChangeWindowAttributesReq *req = 1063 (xChangeWindowAttributesReq *)(client->requestBuffer); 1064 if (req->valueMask == CWEventMask) 1065 { 1066 CARD32 value = *((CARD32 *)(req + 1)); 1067 if ( (value & 1068 ~(PropertyChangeMask|StructureNotifyMask)) == 0) 1069 break; 1070 } 1071 goto deny; 1072 } /* case X_ChangeWindowAttributes on root */ 1073 1074 default: 1075 { 1076 /* others not allowed */ 1077 goto deny; 1078 } 1079 } 1080 } /* end server-owned window or drawable */ 1081 else if (SecurityAuthorizationResType == rtype) 1082 { 1083 SecurityAuthorizationPtr pAuth = (SecurityAuthorizationPtr)rval; 1084 if (pAuth->trustLevel != TRUSTLEVEL(client)) 1085 goto deny; 1086 } 1087 else if (RT_COLORMAP != rtype) 1088 { /* don't allow anything else besides colormaps */ 1089 goto deny; 1090 } 1091 } 1092 return; 1093 deny: 1094 SecurityAuditResourceIDAccess(client, id); 1095 rec->rval = FALSE; /* deny access */ 1096} /* SecurityCheckResourceIDAccess */ 1097 1098 1099/* SecurityClientStateCallback 1100 * 1101 * Arguments: 1102 * pcbl is &ClientStateCallback. 1103 * nullata is NULL. 1104 * calldata is a pointer to a NewClientInfoRec (include/dixstruct.h) 1105 * which contains information about client state changes. 1106 * 1107 * Returns: nothing. 1108 * 1109 * Side Effects: 1110 * 1111 * If a new client is connecting, its authorization ID is copied to 1112 * client->authID. If this is a generated authorization, its reference 1113 * count is bumped, its timer is cancelled if it was running, and its 1114 * trustlevel is copied to TRUSTLEVEL(client). 1115 * 1116 * If a client is disconnecting and the client was using a generated 1117 * authorization, the authorization's reference count is decremented, and 1118 * if it is now zero, the timer for this authorization is started. 1119 */ 1120 1121CALLBACK(SecurityClientStateCallback) 1122{ 1123 NewClientInfoRec *pci = (NewClientInfoRec *)calldata; 1124 ClientPtr client = pci->client; 1125 1126 switch (client->clientState) 1127 { 1128 case ClientStateInitial: 1129 TRUSTLEVEL(client) = XSecurityClientTrusted; 1130 AUTHID(client) = None; 1131 break; 1132 1133 case ClientStateRunning: 1134 { 1135 XID authId = AuthorizationIDOfClient(client); 1136 SecurityAuthorizationPtr pAuth; 1137 1138 TRUSTLEVEL(client) = XSecurityClientTrusted; 1139 AUTHID(client) = authId; 1140 pAuth = (SecurityAuthorizationPtr)LookupIDByType(authId, 1141 SecurityAuthorizationResType); 1142 if (pAuth) 1143 { /* it is a generated authorization */ 1144 pAuth->refcnt++; 1145 if (pAuth->refcnt == 1) 1146 { 1147 if (pAuth->timer) TimerCancel(pAuth->timer); 1148 } 1149 TRUSTLEVEL(client) = pAuth->trustLevel; 1150 } 1151 break; 1152 } 1153 case ClientStateGone: 1154 case ClientStateRetained: /* client disconnected */ 1155 { 1156 SecurityAuthorizationPtr pAuth; 1157 1158 /* client may not have any state (bad authorization) */ 1159 if (!STATEPTR(client)) 1160 break; 1161 1162 pAuth = (SecurityAuthorizationPtr)LookupIDByType(AUTHID(client), 1163 SecurityAuthorizationResType); 1164 if (pAuth) 1165 { /* it is a generated authorization */ 1166 pAuth->refcnt--; 1167 if (pAuth->refcnt == 0) 1168 { 1169 SecurityStartAuthorizationTimer(pAuth); 1170 } 1171 } 1172 break; 1173 } 1174 default: break; 1175 } 1176} /* SecurityClientStateCallback */ 1177 1178CALLBACK(SecurityCheckDrawableAccess) 1179{ 1180 XaceDrawableAccessRec *rec = (XaceDrawableAccessRec*)calldata; 1181 1182 if (TRUSTLEVEL(rec->client) != XSecurityClientTrusted) 1183 rec->rval = FALSE; 1184} 1185 1186CALLBACK(SecurityCheckMapAccess) 1187{ 1188 XaceMapAccessRec *rec = (XaceMapAccessRec*)calldata; 1189 WindowPtr pWin = rec->pWin; 1190 1191 if (STATEPTR(rec->client) && 1192 (TRUSTLEVEL(rec->client) != XSecurityClientTrusted) && 1193 (pWin->drawable.class == InputOnly) && 1194 pWin->parent && pWin->parent->parent && 1195 (TRUSTLEVEL(wClient(pWin->parent)) == XSecurityClientTrusted)) 1196 1197 rec->rval = FALSE; 1198} 1199 1200CALLBACK(SecurityCheckBackgrndAccess) 1201{ 1202 XaceMapAccessRec *rec = (XaceMapAccessRec*)calldata; 1203 1204 if (TRUSTLEVEL(rec->client) != XSecurityClientTrusted) 1205 rec->rval = FALSE; 1206} 1207 1208CALLBACK(SecurityCheckExtAccess) 1209{ 1210 XaceExtAccessRec *rec = (XaceExtAccessRec*)calldata; 1211 1212 if ((TRUSTLEVEL(rec->client) != XSecurityClientTrusted) && 1213 !STATEVAL(rec->ext)) 1214 1215 rec->rval = FALSE; 1216} 1217 1218CALLBACK(SecurityCheckHostlistAccess) 1219{ 1220 XaceHostlistAccessRec *rec = (XaceHostlistAccessRec*)calldata; 1221 1222 if (TRUSTLEVEL(rec->client) != XSecurityClientTrusted) 1223 { 1224 rec->rval = FALSE; 1225 if (rec->access_mode == DixWriteAccess) 1226 SecurityAudit("client %d attempted to change host access\n", 1227 rec->client->index); 1228 else 1229 SecurityAudit("client %d attempted to list hosts\n", 1230 rec->client->index); 1231 } 1232} 1233 1234CALLBACK(SecurityDeclareExtSecure) 1235{ 1236 XaceDeclareExtSecureRec *rec = (XaceDeclareExtSecureRec*)calldata; 1237 1238 /* security state for extensions is simply a boolean trust value */ 1239 STATEVAL(rec->ext) = rec->secure; 1240} 1241 1242/**********************************************************************/ 1243 1244typedef struct _PropertyAccessRec { 1245 ATOM name; 1246 ATOM mustHaveProperty; 1247 char *mustHaveValue; 1248 char windowRestriction; 1249#define SecurityAnyWindow 0 1250#define SecurityRootWindow 1 1251#define SecurityWindowWithProperty 2 1252 char readAction; 1253 char writeAction; 1254 char destroyAction; 1255 struct _PropertyAccessRec *next; 1256} PropertyAccessRec, *PropertyAccessPtr; 1257 1258static PropertyAccessPtr PropertyAccessList = NULL; 1259static char SecurityDefaultAction = XaceErrorOperation; 1260static char *SecurityPolicyFile = DEFAULTPOLICYFILE; 1261static ATOM SecurityMaxPropertyName = 0; 1262 1263static char *SecurityKeywords[] = { 1264#define SecurityKeywordComment 0 1265 "#", 1266#define SecurityKeywordProperty 1 1267 "property", 1268#define SecurityKeywordSitePolicy 2 1269 "sitepolicy", 1270#define SecurityKeywordRoot 3 1271 "root", 1272#define SecurityKeywordAny 4 1273 "any" 1274}; 1275 1276#define NUMKEYWORDS (sizeof(SecurityKeywords) / sizeof(char *)) 1277 1278#undef PROPDEBUG 1279/*#define PROPDEBUG 1*/ 1280 1281static void 1282SecurityFreePropertyAccessList(void) 1283{ 1284 while (PropertyAccessList) 1285 { 1286 PropertyAccessPtr freeit = PropertyAccessList; 1287 PropertyAccessList = PropertyAccessList->next; 1288 xfree(freeit); 1289 } 1290} /* SecurityFreePropertyAccessList */ 1291 1292#define SecurityIsWhitespace(c) ( (c == ' ') || (c == '\t') || (c == '\n') ) 1293 1294static char * 1295SecuritySkipWhitespace( 1296 char *p) 1297{ 1298 while (SecurityIsWhitespace(*p)) 1299 p++; 1300 return p; 1301} /* SecuritySkipWhitespace */ 1302 1303 1304static char * 1305SecurityParseString( 1306 char **rest) 1307{ 1308 char *startOfString; 1309 char *s = *rest; 1310 char endChar = 0; 1311 1312 s = SecuritySkipWhitespace(s); 1313 1314 if (*s == '"' || *s == '\'') 1315 { 1316 endChar = *s++; 1317 startOfString = s; 1318 while (*s && (*s != endChar)) 1319 s++; 1320 } 1321 else 1322 { 1323 startOfString = s; 1324 while (*s && !SecurityIsWhitespace(*s)) 1325 s++; 1326 } 1327 if (*s) 1328 { 1329 *s = '\0'; 1330 *rest = s + 1; 1331 return startOfString; 1332 } 1333 else 1334 { 1335 *rest = s; 1336 return (endChar) ? NULL : startOfString; 1337 } 1338} /* SecurityParseString */ 1339 1340 1341static int 1342SecurityParseKeyword( 1343 char **p) 1344{ 1345 int i; 1346 char *s = *p; 1347 s = SecuritySkipWhitespace(s); 1348 for (i = 0; i < NUMKEYWORDS; i++) 1349 { 1350 int len = strlen(SecurityKeywords[i]); 1351 if (strncmp(s, SecurityKeywords[i], len) == 0) 1352 { 1353 *p = s + len; 1354 return (i); 1355 } 1356 } 1357 *p = s; 1358 return -1; 1359} /* SecurityParseKeyword */ 1360 1361 1362static Bool 1363SecurityParsePropertyAccessRule( 1364 char *p) 1365{ 1366 char *propname; 1367 char c; 1368 char action = SecurityDefaultAction; 1369 char readAction, writeAction, destroyAction; 1370 PropertyAccessPtr pacl, prev, cur; 1371 char *mustHaveProperty = NULL; 1372 char *mustHaveValue = NULL; 1373 Bool invalid; 1374 char windowRestriction; 1375 int size; 1376 int keyword; 1377 1378 /* get property name */ 1379 propname = SecurityParseString(&p); 1380 if (!propname || (strlen(propname) == 0)) 1381 return FALSE; 1382 1383 /* get window on which property must reside for rule to apply */ 1384 1385 keyword = SecurityParseKeyword(&p); 1386 if (keyword == SecurityKeywordRoot) 1387 windowRestriction = SecurityRootWindow; 1388 else if (keyword == SecurityKeywordAny) 1389 windowRestriction = SecurityAnyWindow; 1390 else /* not root or any, must be a property name */ 1391 { 1392 mustHaveProperty = SecurityParseString(&p); 1393 if (!mustHaveProperty || (strlen(mustHaveProperty) == 0)) 1394 return FALSE; 1395 windowRestriction = SecurityWindowWithProperty; 1396 p = SecuritySkipWhitespace(p); 1397 if (*p == '=') 1398 { /* property value is specified too */ 1399 p++; /* skip over '=' */ 1400 mustHaveValue = SecurityParseString(&p); 1401 if (!mustHaveValue) 1402 return FALSE; 1403 } 1404 } 1405 1406 /* get operations and actions */ 1407 1408 invalid = FALSE; 1409 readAction = writeAction = destroyAction = SecurityDefaultAction; 1410 while ( (c = *p++) && !invalid) 1411 { 1412 switch (c) 1413 { 1414 case 'i': action = XaceIgnoreOperation; break; 1415 case 'a': action = XaceAllowOperation; break; 1416 case 'e': action = XaceErrorOperation; break; 1417 1418 case 'r': readAction = action; break; 1419 case 'w': writeAction = action; break; 1420 case 'd': destroyAction = action; break; 1421 1422 default : 1423 if (!SecurityIsWhitespace(c)) 1424 invalid = TRUE; 1425 break; 1426 } 1427 } 1428 if (invalid) 1429 return FALSE; 1430 1431 /* We've successfully collected all the information needed for this 1432 * property access rule. Now record it in a PropertyAccessRec. 1433 */ 1434 size = sizeof(PropertyAccessRec); 1435 1436 /* If there is a property value string, allocate space for it 1437 * right after the PropertyAccessRec. 1438 */ 1439 if (mustHaveValue) 1440 size += strlen(mustHaveValue) + 1; 1441 pacl = (PropertyAccessPtr)Xalloc(size); 1442 if (!pacl) 1443 return FALSE; 1444 1445 pacl->name = MakeAtom(propname, strlen(propname), TRUE); 1446 if (pacl->name == BAD_RESOURCE) 1447 { 1448 Xfree(pacl); 1449 return FALSE; 1450 } 1451 if (mustHaveProperty) 1452 { 1453 pacl->mustHaveProperty = MakeAtom(mustHaveProperty, 1454 strlen(mustHaveProperty), TRUE); 1455 if (pacl->mustHaveProperty == BAD_RESOURCE) 1456 { 1457 Xfree(pacl); 1458 return FALSE; 1459 } 1460 } 1461 else 1462 pacl->mustHaveProperty = 0; 1463 1464 if (mustHaveValue) 1465 { 1466 pacl->mustHaveValue = (char *)(pacl + 1); 1467 strcpy(pacl->mustHaveValue, mustHaveValue); 1468 } 1469 else 1470 pacl->mustHaveValue = NULL; 1471 1472 SecurityMaxPropertyName = max(SecurityMaxPropertyName, pacl->name); 1473 1474 pacl->windowRestriction = windowRestriction; 1475 pacl->readAction = readAction; 1476 pacl->writeAction = writeAction; 1477 pacl->destroyAction = destroyAction; 1478 1479 /* link the new rule into the list of rules in order of increasing 1480 * property name (atom) value to make searching easier 1481 */ 1482 1483 for (prev = NULL, cur = PropertyAccessList; 1484 cur && cur->name <= pacl->name; 1485 prev = cur, cur = cur->next) 1486 ; 1487 if (!prev) 1488 { 1489 pacl->next = cur; 1490 PropertyAccessList = pacl; 1491 } 1492 else 1493 { 1494 prev->next = pacl; 1495 pacl->next = cur; 1496 } 1497 return TRUE; 1498} /* SecurityParsePropertyAccessRule */ 1499 1500static char **SecurityPolicyStrings = NULL; 1501static int nSecurityPolicyStrings = 0; 1502 1503static Bool 1504SecurityParseSitePolicy( 1505 char *p) 1506{ 1507 char *policyStr = SecurityParseString(&p); 1508 char *copyPolicyStr; 1509 char **newStrings; 1510 1511 if (!policyStr) 1512 return FALSE; 1513 1514 copyPolicyStr = (char *)Xalloc(strlen(policyStr) + 1); 1515 if (!copyPolicyStr) 1516 return TRUE; 1517 strcpy(copyPolicyStr, policyStr); 1518 newStrings = (char **)Xrealloc(SecurityPolicyStrings, 1519 sizeof (char *) * (nSecurityPolicyStrings + 1)); 1520 if (!newStrings) 1521 { 1522 Xfree(copyPolicyStr); 1523 return TRUE; 1524 } 1525 1526 SecurityPolicyStrings = newStrings; 1527 SecurityPolicyStrings[nSecurityPolicyStrings++] = copyPolicyStr; 1528 1529 return TRUE; 1530 1531} /* SecurityParseSitePolicy */ 1532 1533 1534char ** 1535SecurityGetSitePolicyStrings(n) 1536 int *n; 1537{ 1538 *n = nSecurityPolicyStrings; 1539 return SecurityPolicyStrings; 1540} /* SecurityGetSitePolicyStrings */ 1541 1542static void 1543SecurityFreeSitePolicyStrings(void) 1544{ 1545 if (SecurityPolicyStrings) 1546 { 1547 assert(nSecurityPolicyStrings); 1548 while (nSecurityPolicyStrings--) 1549 { 1550 Xfree(SecurityPolicyStrings[nSecurityPolicyStrings]); 1551 } 1552 Xfree(SecurityPolicyStrings); 1553 SecurityPolicyStrings = NULL; 1554 nSecurityPolicyStrings = 0; 1555 } 1556} /* SecurityFreeSitePolicyStrings */ 1557 1558 1559static void 1560SecurityLoadPropertyAccessList(void) 1561{ 1562 FILE *f; 1563 int lineNumber = 0; 1564 1565 SecurityMaxPropertyName = 0; 1566 1567 if (!SecurityPolicyFile) 1568 return; 1569 1570 f = Fopen(SecurityPolicyFile, "r"); 1571 if (!f) 1572 { 1573 ErrorF("error opening security policy file %s\n", 1574 SecurityPolicyFile); 1575 return; 1576 } 1577 1578 while (!feof(f)) 1579 { 1580 char buf[200]; 1581 Bool validLine; 1582 char *p; 1583 1584 if (!(p = fgets(buf, sizeof(buf), f))) 1585 break; 1586 lineNumber++; 1587 1588 /* if first line, check version number */ 1589 if (lineNumber == 1) 1590 { 1591 char *v = SecurityParseString(&p); 1592 if (strcmp(v, SECURITY_POLICY_FILE_VERSION) != 0) 1593 { 1594 ErrorF("%s: invalid security policy file version, ignoring file\n", 1595 SecurityPolicyFile); 1596 break; 1597 } 1598 validLine = TRUE; 1599 } 1600 else 1601 { 1602 switch (SecurityParseKeyword(&p)) 1603 { 1604 case SecurityKeywordComment: 1605 validLine = TRUE; 1606 break; 1607 1608 case SecurityKeywordProperty: 1609 validLine = SecurityParsePropertyAccessRule(p); 1610 break; 1611 1612 case SecurityKeywordSitePolicy: 1613 validLine = SecurityParseSitePolicy(p); 1614 break; 1615 1616 default: 1617 validLine = (*p == '\0'); /* blank lines OK, others not */ 1618 break; 1619 } 1620 } 1621 1622 if (!validLine) 1623 ErrorF("Line %d of %s invalid, ignoring\n", 1624 lineNumber, SecurityPolicyFile); 1625 } /* end while more input */ 1626 1627#ifdef PROPDEBUG 1628 { 1629 PropertyAccessPtr pacl; 1630 char *op = "aie"; 1631 for (pacl = PropertyAccessList; pacl; pacl = pacl->next) 1632 { 1633 ErrorF("property %s ", NameForAtom(pacl->name)); 1634 switch (pacl->windowRestriction) 1635 { 1636 case SecurityAnyWindow: ErrorF("any "); break; 1637 case SecurityRootWindow: ErrorF("root "); break; 1638 case SecurityWindowWithProperty: 1639 { 1640 ErrorF("%s ", NameForAtom(pacl->mustHaveProperty)); 1641 if (pacl->mustHaveValue) 1642 ErrorF(" = \"%s\" ", pacl->mustHaveValue); 1643 1644 } 1645 break; 1646 } 1647 ErrorF("%cr %cw %cd\n", op[pacl->readAction], 1648 op[pacl->writeAction], op[pacl->destroyAction]); 1649 } 1650 } 1651#endif /* PROPDEBUG */ 1652 1653 Fclose(f); 1654} /* SecurityLoadPropertyAccessList */ 1655 1656 1657static Bool 1658SecurityMatchString( 1659 char *ws, 1660 char *cs) 1661{ 1662 while (*ws && *cs) 1663 { 1664 if (*ws == '*') 1665 { 1666 Bool match = FALSE; 1667 ws++; 1668 while (!(match = SecurityMatchString(ws, cs)) && *cs) 1669 { 1670 cs++; 1671 } 1672 return match; 1673 } 1674 else if (*ws == *cs) 1675 { 1676 ws++; 1677 cs++; 1678 } 1679 else break; 1680 } 1681 return ( ( (*ws == '\0') || ((*ws == '*') && *(ws+1) == '\0') ) 1682 && (*cs == '\0') ); 1683} /* SecurityMatchString */ 1684 1685#ifdef PROPDEBUG 1686#include <sys/types.h> 1687#include <sys/stat.h> 1688#endif 1689 1690 1691CALLBACK(SecurityCheckPropertyAccess) 1692{ 1693 XacePropertyAccessRec *rec = (XacePropertyAccessRec*)calldata; 1694 ClientPtr client = rec->client; 1695 WindowPtr pWin = rec->pWin; 1696 ATOM propertyName = rec->propertyName; 1697 Mask access_mode = rec->access_mode; 1698 PropertyAccessPtr pacl; 1699 char action = SecurityDefaultAction; 1700 1701 /* if client trusted or window untrusted, allow operation */ 1702 1703 if ( (TRUSTLEVEL(client) == XSecurityClientTrusted) || 1704 (TRUSTLEVEL(wClient(pWin)) != XSecurityClientTrusted) ) 1705 return; 1706 1707#ifdef PROPDEBUG 1708 /* For testing, it's more convenient if the property rules file gets 1709 * reloaded whenever it changes, so we can rapidly try things without 1710 * having to reset the server. 1711 */ 1712 { 1713 struct stat buf; 1714 static time_t lastmod = 0; 1715 int ret = stat(SecurityPolicyFile , &buf); 1716 if ( (ret == 0) && (buf.st_mtime > lastmod) ) 1717 { 1718 ErrorF("reloading property rules\n"); 1719 SecurityFreePropertyAccessList(); 1720 SecurityLoadPropertyAccessList(); 1721 lastmod = buf.st_mtime; 1722 } 1723 } 1724#endif 1725 1726 /* If the property atom is bigger than any atoms on the list, 1727 * we know we won't find it, so don't even bother looking. 1728 */ 1729 if (propertyName <= SecurityMaxPropertyName) 1730 { 1731 /* untrusted client operating on trusted window; see if it's allowed */ 1732 1733 for (pacl = PropertyAccessList; pacl; pacl = pacl->next) 1734 { 1735 if (pacl->name < propertyName) 1736 continue; 1737 if (pacl->name > propertyName) 1738 break; 1739 1740 /* pacl->name == propertyName, so see if it applies to this window */ 1741 1742 switch (pacl->windowRestriction) 1743 { 1744 case SecurityAnyWindow: /* always applies */ 1745 break; 1746 1747 case SecurityRootWindow: 1748 { 1749 /* if not a root window, this rule doesn't apply */ 1750 if (pWin->parent) 1751 continue; 1752 } 1753 break; 1754 1755 case SecurityWindowWithProperty: 1756 { 1757 PropertyPtr pProp = wUserProps (pWin); 1758 Bool match = FALSE; 1759 char *p; 1760 char *pEndData; 1761 1762 while (pProp) 1763 { 1764 if (pProp->propertyName == pacl->mustHaveProperty) 1765 break; 1766 pProp = pProp->next; 1767 } 1768 if (!pProp) 1769 continue; 1770 if (!pacl->mustHaveValue) 1771 break; 1772 if (pProp->type != XA_STRING || pProp->format != 8) 1773 continue; 1774 1775 p = pProp->data; 1776 pEndData = ((char *)pProp->data) + pProp->size; 1777 while (!match && p < pEndData) 1778 { 1779 if (SecurityMatchString(pacl->mustHaveValue, p)) 1780 match = TRUE; 1781 else 1782 { /* skip to the next string */ 1783 while (*p++ && p < pEndData) 1784 ; 1785 } 1786 } 1787 if (!match) 1788 continue; 1789 } 1790 break; /* end case SecurityWindowWithProperty */ 1791 } /* end switch on windowRestriction */ 1792 1793 /* If we get here, the property access rule pacl applies. 1794 * If pacl doesn't apply, something above should have 1795 * executed a continue, which will skip the follwing code. 1796 */ 1797 action = XaceAllowOperation; 1798 if (access_mode & DixReadAccess) 1799 action = max(action, pacl->readAction); 1800 if (access_mode & DixWriteAccess) 1801 action = max(action, pacl->writeAction); 1802 if (access_mode & DixDestroyAccess) 1803 action = max(action, pacl->destroyAction); 1804 break; 1805 } /* end for each pacl */ 1806 } /* end if propertyName <= SecurityMaxPropertyName */ 1807 1808 if (XaceAllowOperation != action) 1809 { /* audit the access violation */ 1810 int cid = CLIENT_ID(pWin->drawable.id); 1811 int reqtype = ((xReq *)client->requestBuffer)->reqType; 1812 char *actionstr = (XaceIgnoreOperation == action) ? 1813 "ignored" : "error"; 1814 SecurityAudit("client %d attempted request %d with window 0x%x property %s (atom 0x%x) of client %d, %s\n", 1815 client->index, reqtype, pWin->drawable.id, 1816 NameForAtom(propertyName), propertyName, cid, actionstr); 1817 } 1818 /* return codes increase with strictness */ 1819 if (action > rec->rval) 1820 rec->rval = action; 1821} /* SecurityCheckPropertyAccess */ 1822 1823 1824/* SecurityResetProc 1825 * 1826 * Arguments: 1827 * extEntry is the extension information for the security extension. 1828 * 1829 * Returns: nothing. 1830 * 1831 * Side Effects: 1832 * Performs any cleanup needed by Security at server shutdown time. 1833 */ 1834 1835static void 1836SecurityResetProc( 1837 ExtensionEntry *extEntry) 1838{ 1839 SecurityFreePropertyAccessList(); 1840 SecurityFreeSitePolicyStrings(); 1841} /* SecurityResetProc */ 1842 1843 1844int 1845XSecurityOptions(argc, argv, i) 1846 int argc; 1847 char **argv; 1848 int i; 1849{ 1850 if (strcmp(argv[i], "-sp") == 0) 1851 { 1852 if (i < argc) 1853 SecurityPolicyFile = argv[++i]; 1854 return (i + 1); 1855 } 1856 return (i); 1857} /* XSecurityOptions */ 1858 1859 1860/* SecurityExtensionSetup 1861 * 1862 * Arguments: none. 1863 * 1864 * Returns: nothing. 1865 * 1866 * Side Effects: 1867 * Sets up the Security extension if possible. 1868 * This function contains things that need to be done 1869 * before any other extension init functions get called. 1870 */ 1871 1872void 1873SecurityExtensionSetup(INITARGS) 1874{ 1875 /* Allocate the client private index */ 1876 securityClientPrivateIndex = AllocateClientPrivateIndex(); 1877 if (!AllocateClientPrivate(securityClientPrivateIndex, 1878 sizeof (SecurityClientStateRec))) 1879 FatalError("SecurityExtensionSetup: Can't allocate client private.\n"); 1880 1881 /* Allocate the extension private index */ 1882 securityExtnsnPrivateIndex = AllocateExtensionPrivateIndex(); 1883 if (!AllocateExtensionPrivate(securityExtnsnPrivateIndex, 0)) 1884 FatalError("SecurityExtensionSetup: Can't allocate extnsn private.\n"); 1885 1886 /* register callbacks */ 1887#define XaceRC XaceRegisterCallback 1888 XaceRC(XACE_RESOURCE_ACCESS, SecurityCheckResourceIDAccess, NULL); 1889 XaceRC(XACE_DEVICE_ACCESS, SecurityCheckDeviceAccess, NULL); 1890 XaceRC(XACE_PROPERTY_ACCESS, SecurityCheckPropertyAccess, NULL); 1891 XaceRC(XACE_DRAWABLE_ACCESS, SecurityCheckDrawableAccess, NULL); 1892 XaceRC(XACE_MAP_ACCESS, SecurityCheckMapAccess, NULL); 1893 XaceRC(XACE_BACKGRND_ACCESS, SecurityCheckBackgrndAccess, NULL); 1894 XaceRC(XACE_EXT_DISPATCH, SecurityCheckExtAccess, NULL); 1895 XaceRC(XACE_EXT_ACCESS, SecurityCheckExtAccess, NULL); 1896 XaceRC(XACE_HOSTLIST_ACCESS, SecurityCheckHostlistAccess, NULL); 1897 XaceRC(XACE_DECLARE_EXT_SECURE, SecurityDeclareExtSecure, NULL); 1898} /* SecurityExtensionSetup */ 1899 1900 1901/* SecurityExtensionInit 1902 * 1903 * Arguments: none. 1904 * 1905 * Returns: nothing. 1906 * 1907 * Side Effects: 1908 * Enables the Security extension if possible. 1909 */ 1910 1911void 1912SecurityExtensionInit(INITARGS) 1913{ 1914 ExtensionEntry *extEntry; 1915 1916 SecurityAuthorizationResType = 1917 CreateNewResourceType(SecurityDeleteAuthorization); 1918 1919 RTEventClient = CreateNewResourceType( 1920 SecurityDeleteAuthorizationEventClient); 1921 1922 if (!SecurityAuthorizationResType || !RTEventClient) 1923 return; 1924 1925 RTEventClient |= RC_NEVERRETAIN; 1926 1927 if (!AddCallback(&ClientStateCallback, SecurityClientStateCallback, NULL)) 1928 return; 1929 1930 extEntry = AddExtension(SECURITY_EXTENSION_NAME, 1931 XSecurityNumberEvents, XSecurityNumberErrors, 1932 ProcSecurityDispatch, SProcSecurityDispatch, 1933 SecurityResetProc, StandardMinorOpcode); 1934 1935 SecurityErrorBase = extEntry->errorBase; 1936 SecurityEventBase = extEntry->eventBase; 1937 1938 EventSwapVector[SecurityEventBase + XSecurityAuthorizationRevoked] = 1939 (EventSwapPtr)SwapSecurityAuthorizationRevokedEvent; 1940 1941 SecurityLoadPropertyAccessList(); 1942 1943} /* SecurityExtensionInit */ 1944