1caade7ccSmrg/*
2caade7ccSmrg
3caade7ccSmrgCopyright 1996, 1998  The Open Group
4caade7ccSmrg
5caade7ccSmrgPermission to use, copy, modify, distribute, and sell this software and its
6caade7ccSmrgdocumentation for any purpose is hereby granted without fee, provided that
7caade7ccSmrgthe above copyright notice appear in all copies and that both that
8caade7ccSmrgcopyright notice and this permission notice appear in supporting
9caade7ccSmrgdocumentation.
10caade7ccSmrg
11caade7ccSmrgThe above copyright notice and this permission notice shall be included in
12caade7ccSmrgall copies or substantial portions of the Software.
13caade7ccSmrg
14caade7ccSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15caade7ccSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16caade7ccSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17caade7ccSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18caade7ccSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19caade7ccSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20caade7ccSmrg
21caade7ccSmrgExcept as contained in this notice, the name of The Open Group shall not be
22caade7ccSmrgused in advertising or otherwise to promote the sale, use or other dealings
23caade7ccSmrgin this Software without prior written authorization from The Open Group.
24caade7ccSmrg
25caade7ccSmrg*/
26caade7ccSmrg
27caade7ccSmrg#ifdef HAVE_CONFIG_H
28caade7ccSmrg#include <config.h>
29caade7ccSmrg#endif
30caade7ccSmrg#include <X11/Xlibint.h>
31caade7ccSmrg#include <stdio.h>
32caade7ccSmrg#include <X11/extensions/Xext.h>
33caade7ccSmrg#include <X11/extensions/extutil.h>
34485f0483Smrg#include <X11/extensions/securproto.h>
35485f0483Smrg#include <X11/extensions/security.h>
36cc4920e5Smrg#include <assert.h>
37caade7ccSmrg
38caade7ccSmrgstatic XExtensionInfo _Security_info_data;
39caade7ccSmrgstatic XExtensionInfo *Security_info = &_Security_info_data;
40af9a7ee5Smrgstatic const char *Security_extension_name = SECURITY_EXTENSION_NAME;
41caade7ccSmrg
42caade7ccSmrg#define SecurityCheckExtension(dpy,i,val) \
43caade7ccSmrg  XextCheckExtension (dpy, i, Security_extension_name, val)
44caade7ccSmrg#define SecuritySimpleCheckExtension(dpy,i) \
45caade7ccSmrg  XextSimpleCheckExtension (dpy, i, Security_extension_name)
46caade7ccSmrg
47caade7ccSmrg#define SecurityGetReq(name,req,info) GetReq (name, req); \
48caade7ccSmrg        req->reqType = info->codes->major_opcode; \
49caade7ccSmrg        req->securityReqType = X_##name;
50caade7ccSmrg
51caade7ccSmrg/*****************************************************************************
52caade7ccSmrg *                                                                           *
53caade7ccSmrg *			   private utility routines                          *
54caade7ccSmrg *                                                                           *
55caade7ccSmrg *****************************************************************************/
56caade7ccSmrg
57caade7ccSmrg/*
58caade7ccSmrg * find_display - locate the display info block
59caade7ccSmrg */
60caade7ccSmrgstatic int close_display(Display *dpy, XExtCodes *codes);
61caade7ccSmrgstatic Bool wire_to_event(Display *dpy, XEvent *event, xEvent *wire);
62caade7ccSmrgstatic Status event_to_wire(Display *dpy, XEvent *event, xEvent *wire);
63caade7ccSmrgstatic char *error_string(Display *dpy, int code, XExtCodes *codes,
64caade7ccSmrg			  char *buf, int n);
65caade7ccSmrg
66caade7ccSmrgstatic XExtensionHooks Security_extension_hooks = {
67caade7ccSmrg    NULL,                               /* create_gc */
68caade7ccSmrg    NULL,                               /* copy_gc */
69caade7ccSmrg    NULL,                               /* flush_gc */
70caade7ccSmrg    NULL,                               /* free_gc */
71caade7ccSmrg    NULL,                               /* create_font */
72caade7ccSmrg    NULL,                               /* free_font */
73caade7ccSmrg    close_display,                      /* close_display */
74caade7ccSmrg    wire_to_event,                      /* wire_to_event */
75caade7ccSmrg    event_to_wire,                      /* event_to_wire */
76caade7ccSmrg    NULL,                               /* error */
77caade7ccSmrg    error_string                        /* error_string */
78caade7ccSmrg};
79caade7ccSmrg
80af9a7ee5Smrgstatic const char    *security_error_list[] = {
81caade7ccSmrg    "BadAuthorization",
82caade7ccSmrg    "BadAuthorizationProtocol"
83caade7ccSmrg};
84caade7ccSmrg
85caade7ccSmrgstatic XEXT_GENERATE_FIND_DISPLAY (find_display, Security_info,
86caade7ccSmrg				   Security_extension_name,
87caade7ccSmrg				   &Security_extension_hooks,
88caade7ccSmrg				   XSecurityNumberEvents, NULL)
89caade7ccSmrg
90caade7ccSmrgstatic XEXT_GENERATE_CLOSE_DISPLAY (close_display, Security_info)
91caade7ccSmrg
92caade7ccSmrgstatic
93caade7ccSmrgXEXT_GENERATE_ERROR_STRING(error_string, Security_extension_name,
94caade7ccSmrg			   XSecurityNumberErrors, security_error_list)
95caade7ccSmrg
96caade7ccSmrgstatic Bool
97caade7ccSmrgwire_to_event(Display *dpy, XEvent *event, xEvent *wire)
98caade7ccSmrg{
99caade7ccSmrg    XExtDisplayInfo *info = find_display(dpy);
100caade7ccSmrg
101caade7ccSmrg    SecurityCheckExtension (dpy, info, False);
102caade7ccSmrg
103caade7ccSmrg    switch ((wire->u.u.type & 0x7F) - info->codes->first_event)
104caade7ccSmrg    {
105caade7ccSmrg	case XSecurityAuthorizationRevoked:
106caade7ccSmrg	{
107caade7ccSmrg	    xSecurityAuthorizationRevokedEvent *rwire =
108caade7ccSmrg		(xSecurityAuthorizationRevokedEvent *)wire;
109caade7ccSmrg	    XSecurityAuthorizationRevokedEvent *revent =
110caade7ccSmrg		(XSecurityAuthorizationRevokedEvent *)event;
111caade7ccSmrg
112caade7ccSmrg	  revent->type = rwire->type & 0x7F;
113caade7ccSmrg	  revent->serial = _XSetLastRequestRead(dpy,
114caade7ccSmrg						(xGenericReply *) wire);
115caade7ccSmrg	  revent->send_event = (rwire->type & 0x80) != 0;
116caade7ccSmrg	  revent->display = dpy;
117caade7ccSmrg	  revent->auth_id = rwire->authId;
118caade7ccSmrg	  return True;
119caade7ccSmrg	}
120caade7ccSmrg    }
121caade7ccSmrg    return False;
122caade7ccSmrg}
123caade7ccSmrg
124caade7ccSmrgstatic Status
125caade7ccSmrgevent_to_wire(Display *dpy, XEvent *event, xEvent *wire)
126caade7ccSmrg{
127caade7ccSmrg    XExtDisplayInfo *info = find_display(dpy);
128caade7ccSmrg
129caade7ccSmrg    SecurityCheckExtension(dpy, info, False);
130caade7ccSmrg
131caade7ccSmrg    switch ((event->type & 0x7F) - info->codes->first_event)
132caade7ccSmrg    {
133caade7ccSmrg	case XSecurityAuthorizationRevoked:
134caade7ccSmrg	{
135caade7ccSmrg	    xSecurityAuthorizationRevokedEvent *rwire =
136caade7ccSmrg		(xSecurityAuthorizationRevokedEvent *)wire;
137caade7ccSmrg	    XSecurityAuthorizationRevokedEvent *revent =
138caade7ccSmrg		(XSecurityAuthorizationRevokedEvent *)event;
139caade7ccSmrg	    rwire->type = revent->type | (revent->send_event ? 0x80 : 0);
140caade7ccSmrg	    rwire->sequenceNumber = revent->serial & 0xFFFF;
141caade7ccSmrg	    return True;
142caade7ccSmrg	}
143caade7ccSmrg    }
144caade7ccSmrg    return False;
145caade7ccSmrg}
146caade7ccSmrg
147caade7ccSmrg/*****************************************************************************
148caade7ccSmrg *                                                                           *
149caade7ccSmrg *		       Security public interfaces                            *
150caade7ccSmrg *                                                                           *
151caade7ccSmrg *****************************************************************************/
152caade7ccSmrg
153caade7ccSmrgStatus XSecurityQueryExtension (
154caade7ccSmrg    Display *dpy,
155caade7ccSmrg    int *major_version_return,
156caade7ccSmrg    int *minor_version_return)
157caade7ccSmrg{
158caade7ccSmrg    XExtDisplayInfo *info = find_display (dpy);
159caade7ccSmrg    xSecurityQueryVersionReply rep;
160caade7ccSmrg    register xSecurityQueryVersionReq *req;
161caade7ccSmrg
162caade7ccSmrg    if (!XextHasExtension (info))
163caade7ccSmrg        return (Status)0; /* failure */
164caade7ccSmrg
165caade7ccSmrg    LockDisplay (dpy);
166caade7ccSmrg    SecurityGetReq (SecurityQueryVersion, req, info);
167caade7ccSmrg    req->majorVersion = SECURITY_MAJOR_VERSION;
168caade7ccSmrg    req->minorVersion = SECURITY_MINOR_VERSION;
169caade7ccSmrg
170caade7ccSmrg    if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
171caade7ccSmrg	UnlockDisplay (dpy);
172caade7ccSmrg	SyncHandle ();
173caade7ccSmrg	return (Status)0; /* failure */
174caade7ccSmrg    }
175caade7ccSmrg    *major_version_return = rep.majorVersion;
176caade7ccSmrg    *minor_version_return = rep.minorVersion;
177caade7ccSmrg    UnlockDisplay (dpy);
178caade7ccSmrg
179caade7ccSmrg    SyncHandle ();
180caade7ccSmrg
181caade7ccSmrg    if (*major_version_return != SECURITY_MAJOR_VERSION)
182caade7ccSmrg        return (Status)0; /* failure */
183caade7ccSmrg    else
184caade7ccSmrg        return (Status)1; /* success */
185caade7ccSmrg}
186caade7ccSmrg
187caade7ccSmrgXauth *
188caade7ccSmrgXSecurityAllocXauth(void)
189caade7ccSmrg{
190caade7ccSmrg    return Xcalloc(1, sizeof(Xauth));
191caade7ccSmrg}
192caade7ccSmrg
193caade7ccSmrgvoid
194caade7ccSmrgXSecurityFreeXauth(Xauth *auth)
195caade7ccSmrg{
196caade7ccSmrg    XFree(auth);
197caade7ccSmrg}
198caade7ccSmrg
199cc4920e5Smrg#ifdef HAVE___BUILTIN_POPCOUNTL
200cc4920e5Smrg# define Ones __builtin_popcountl
201cc4920e5Smrg#else
202cc4920e5Smrg/*
203cc4920e5Smrg * Count the number of bits set to 1 in a 32-bit word.
204cc4920e5Smrg * Algorithm from MIT AI Lab Memo 239: "HAKMEM", ITEM 169.
205cc4920e5Smrg * http://dspace.mit.edu/handle/1721.1/6086
206cc4920e5Smrg */
207cc4920e5Smrgstatic inline int
208caade7ccSmrgOnes(Mask mask)
209caade7ccSmrg{
210caade7ccSmrg    register Mask y;
211caade7ccSmrg
212cc4920e5Smrg    y = (mask >> 1) & 033333333333;
213caade7ccSmrg    y = mask - y - ((y >>1) & 033333333333);
214caade7ccSmrg    return (((y + (y >> 3)) & 030707070707) % 077);
215caade7ccSmrg}
216cc4920e5Smrg#endif
217caade7ccSmrg
218caade7ccSmrgXauth *
219caade7ccSmrgXSecurityGenerateAuthorization(
220caade7ccSmrg    Display *dpy,
221caade7ccSmrg    Xauth *auth_in,
222caade7ccSmrg    unsigned long valuemask,
223caade7ccSmrg    XSecurityAuthorizationAttributes *attributes,
224caade7ccSmrg    XSecurityAuthorization *auth_id_return)
225caade7ccSmrg{
226caade7ccSmrg    XExtDisplayInfo *info = find_display (dpy);
227caade7ccSmrg    register xSecurityGenerateAuthorizationReq *req;
228caade7ccSmrg    xSecurityGenerateAuthorizationReply rep;
229caade7ccSmrg    Xauth *auth_return;
230cc4920e5Smrg    unsigned long values[4];
231caade7ccSmrg    unsigned long *value = values;
232caade7ccSmrg    unsigned int nvalues;
233caade7ccSmrg
234cc4920e5Smrg    /* values array must have a slot for each possible valuemask value */
235cc4920e5Smrg    assert(Ones(XSecurityAllAuthorizationAttributes)
236cc4920e5Smrg           == (sizeof(values) / sizeof(values[0])));
237cc4920e5Smrg
238caade7ccSmrg    *auth_id_return = 0;  /* in case we fail */
239caade7ccSmrg
240caade7ccSmrg    /* make sure extension is available */
241caade7ccSmrg
242caade7ccSmrg    SecurityCheckExtension (dpy, info, (Xauth *)NULL);
243caade7ccSmrg
244caade7ccSmrg    LockDisplay(dpy);
245caade7ccSmrg    SecurityGetReq(SecurityGenerateAuthorization, req, info);
246caade7ccSmrg
247caade7ccSmrg    req->nbytesAuthProto = auth_in->name_length;
248caade7ccSmrg    req->nbytesAuthData  = auth_in->data_length;
249caade7ccSmrg
250caade7ccSmrg    /* adjust length to account for auth name and data */
251caade7ccSmrg    req->length += (auth_in->name_length + (unsigned)3) >> 2;
252caade7ccSmrg    req->length += (auth_in->data_length + (unsigned)3) >> 2;
253caade7ccSmrg
254caade7ccSmrg    /* adjust length to account for list of values */
255caade7ccSmrg    req->valueMask = valuemask & XSecurityAllAuthorizationAttributes;
256caade7ccSmrg    nvalues = Ones(req->valueMask);
257caade7ccSmrg    req->length += nvalues;
258caade7ccSmrg
259caade7ccSmrg    /* send auth name and data */
260caade7ccSmrg    Data(dpy, auth_in->name, auth_in->name_length);
261caade7ccSmrg    Data(dpy, auth_in->data, auth_in->data_length);
262caade7ccSmrg
263caade7ccSmrg    /* send values */
264caade7ccSmrg    if (valuemask & XSecurityTimeout)	 *value++ = attributes->timeout;
265caade7ccSmrg    if (valuemask & XSecurityTrustLevel) *value++ = attributes->trust_level;
266caade7ccSmrg    if (valuemask & XSecurityGroup)	 *value++ = attributes->group;
267caade7ccSmrg    if (valuemask & XSecurityEventMask)	 *value++ = attributes->event_mask;
268caade7ccSmrg
269caade7ccSmrg    nvalues <<= 2;
270caade7ccSmrg    Data32(dpy, (long *)values, (long)nvalues);
271caade7ccSmrg
272caade7ccSmrg    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) {
273caade7ccSmrg	UnlockDisplay (dpy);
274caade7ccSmrg	SyncHandle ();
275caade7ccSmrg	return (Xauth *)NULL;
276caade7ccSmrg    }
277caade7ccSmrg
278caade7ccSmrg    *auth_id_return = rep.authId;
279caade7ccSmrg
280caade7ccSmrg    /* Allocate space for the Xauth struct and the auth name and data all
281caade7ccSmrg     * in one hunk.  This lets XSecurityFreeXauth not have to care
282caade7ccSmrg     * about whether the auth was allocated here or in
283caade7ccSmrg     * XSecurityAllocXauth; in both cases, you just free one pointer.
284caade7ccSmrg     */
285caade7ccSmrg
2860760f5d2Smrg    if ((auth_return = Xcalloc(1,
287caade7ccSmrg		(sizeof(Xauth) + auth_in->name_length + rep.dataLength))))
288caade7ccSmrg    {
289caade7ccSmrg	auth_return->data_length = rep.dataLength;
290caade7ccSmrg	auth_return->data = (char *)&auth_return[1];
291caade7ccSmrg	_XReadPad(dpy, auth_return->data, (long)rep.dataLength);
292caade7ccSmrg
293caade7ccSmrg	auth_return->name_length = auth_in->name_length;
294caade7ccSmrg	auth_return->name = auth_return->data + auth_return->data_length;
295caade7ccSmrg	memcpy(auth_return->name, auth_in->name, auth_return->name_length);
296caade7ccSmrg    }
297caade7ccSmrg    else
298caade7ccSmrg    {
299af9a7ee5Smrg	_XEatDataWords(dpy, rep.length);
300caade7ccSmrg    }
301caade7ccSmrg
302caade7ccSmrg    UnlockDisplay (dpy);
303caade7ccSmrg    SyncHandle ();
304caade7ccSmrg    return auth_return;
305caade7ccSmrg
306caade7ccSmrg} /* XSecurityGenerateAuthorization */
307caade7ccSmrg
308caade7ccSmrgStatus
309caade7ccSmrgXSecurityRevokeAuthorization(
310caade7ccSmrg    Display *dpy,
311caade7ccSmrg    XSecurityAuthorization auth_id)
312caade7ccSmrg{
313caade7ccSmrg    XExtDisplayInfo *info = find_display (dpy);
314caade7ccSmrg    xSecurityRevokeAuthorizationReq *req;
315caade7ccSmrg
316caade7ccSmrg    SecurityCheckExtension (dpy, info, 0);
317caade7ccSmrg    LockDisplay(dpy);
318caade7ccSmrg    SecurityGetReq(SecurityRevokeAuthorization, req, info);
319caade7ccSmrg    req->authId = auth_id;
320caade7ccSmrg    UnlockDisplay (dpy);
321caade7ccSmrg    SyncHandle ();
322caade7ccSmrg    return 1;
323caade7ccSmrg} /* XSecurityRevokeAuthorization */
324