~ubuntu-branches/ubuntu/intrepid/xserver-xgl/intrepid

« back to all changes in this revision

Viewing changes to Xext/security.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthew Garrett
  • Date: 2006-02-13 14:21:43 UTC
  • Revision ID: james.westby@ubuntu.com-20060213142143-mad6z9xzem7hzxz9
Tags: upstream-7.0.0
ImportĀ upstreamĀ versionĀ 7.0.0

Show diffs side-by-side

added added

removed removed

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