XSecurity.c revision cc4920e5
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_CONFIG_H
28#include <config.h>
29#endif
30#include <X11/Xlibint.h>
31#include <stdio.h>
32#include <X11/extensions/Xext.h>
33#include <X11/extensions/extutil.h>
34#include <X11/extensions/securproto.h>
35#include <X11/extensions/security.h>
36#include <assert.h>
37
38static XExtensionInfo _Security_info_data;
39static XExtensionInfo *Security_info = &_Security_info_data;
40static const char *Security_extension_name = SECURITY_EXTENSION_NAME;
41
42#define SecurityCheckExtension(dpy,i,val) \
43  XextCheckExtension (dpy, i, Security_extension_name, val)
44#define SecuritySimpleCheckExtension(dpy,i) \
45  XextSimpleCheckExtension (dpy, i, Security_extension_name)
46
47#define SecurityGetReq(name,req,info) GetReq (name, req); \
48        req->reqType = info->codes->major_opcode; \
49        req->securityReqType = X_##name;
50
51/*****************************************************************************
52 *                                                                           *
53 *			   private utility routines                          *
54 *                                                                           *
55 *****************************************************************************/
56
57/*
58 * find_display - locate the display info block
59 */
60static int close_display(Display *dpy, XExtCodes *codes);
61static Bool wire_to_event(Display *dpy, XEvent *event, xEvent *wire);
62static Status event_to_wire(Display *dpy, XEvent *event, xEvent *wire);
63static char *error_string(Display *dpy, int code, XExtCodes *codes,
64			  char *buf, int n);
65
66static XExtensionHooks Security_extension_hooks = {
67    NULL,                               /* create_gc */
68    NULL,                               /* copy_gc */
69    NULL,                               /* flush_gc */
70    NULL,                               /* free_gc */
71    NULL,                               /* create_font */
72    NULL,                               /* free_font */
73    close_display,                      /* close_display */
74    wire_to_event,                      /* wire_to_event */
75    event_to_wire,                      /* event_to_wire */
76    NULL,                               /* error */
77    error_string                        /* error_string */
78};
79
80static const char    *security_error_list[] = {
81    "BadAuthorization",
82    "BadAuthorizationProtocol"
83};
84
85static XEXT_GENERATE_FIND_DISPLAY (find_display, Security_info,
86				   Security_extension_name,
87				   &Security_extension_hooks,
88				   XSecurityNumberEvents, NULL)
89
90static XEXT_GENERATE_CLOSE_DISPLAY (close_display, Security_info)
91
92static
93XEXT_GENERATE_ERROR_STRING(error_string, Security_extension_name,
94			   XSecurityNumberErrors, security_error_list)
95
96static Bool
97wire_to_event(Display *dpy, XEvent *event, xEvent *wire)
98{
99    XExtDisplayInfo *info = find_display(dpy);
100
101    SecurityCheckExtension (dpy, info, False);
102
103    switch ((wire->u.u.type & 0x7F) - info->codes->first_event)
104    {
105	case XSecurityAuthorizationRevoked:
106	{
107	    xSecurityAuthorizationRevokedEvent *rwire =
108		(xSecurityAuthorizationRevokedEvent *)wire;
109	    XSecurityAuthorizationRevokedEvent *revent =
110		(XSecurityAuthorizationRevokedEvent *)event;
111
112	  revent->type = rwire->type & 0x7F;
113	  revent->serial = _XSetLastRequestRead(dpy,
114						(xGenericReply *) wire);
115	  revent->send_event = (rwire->type & 0x80) != 0;
116	  revent->display = dpy;
117	  revent->auth_id = rwire->authId;
118	  return True;
119	}
120    }
121    return False;
122}
123
124static Status
125event_to_wire(Display *dpy, XEvent *event, xEvent *wire)
126{
127    XExtDisplayInfo *info = find_display(dpy);
128
129    SecurityCheckExtension(dpy, info, False);
130
131    switch ((event->type & 0x7F) - info->codes->first_event)
132    {
133	case XSecurityAuthorizationRevoked:
134	{
135	    xSecurityAuthorizationRevokedEvent *rwire =
136		(xSecurityAuthorizationRevokedEvent *)wire;
137	    XSecurityAuthorizationRevokedEvent *revent =
138		(XSecurityAuthorizationRevokedEvent *)event;
139	    rwire->type = revent->type | (revent->send_event ? 0x80 : 0);
140	    rwire->sequenceNumber = revent->serial & 0xFFFF;
141	    return True;
142	}
143    }
144    return False;
145}
146
147/*****************************************************************************
148 *                                                                           *
149 *		       Security public interfaces                            *
150 *                                                                           *
151 *****************************************************************************/
152
153Status XSecurityQueryExtension (
154    Display *dpy,
155    int *major_version_return,
156    int *minor_version_return)
157{
158    XExtDisplayInfo *info = find_display (dpy);
159    xSecurityQueryVersionReply rep;
160    register xSecurityQueryVersionReq *req;
161
162    if (!XextHasExtension (info))
163        return (Status)0; /* failure */
164
165    LockDisplay (dpy);
166    SecurityGetReq (SecurityQueryVersion, req, info);
167    req->majorVersion = SECURITY_MAJOR_VERSION;
168    req->minorVersion = SECURITY_MINOR_VERSION;
169
170    if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
171	UnlockDisplay (dpy);
172	SyncHandle ();
173	return (Status)0; /* failure */
174    }
175    *major_version_return = rep.majorVersion;
176    *minor_version_return = rep.minorVersion;
177    UnlockDisplay (dpy);
178
179    SyncHandle ();
180
181    if (*major_version_return != SECURITY_MAJOR_VERSION)
182        return (Status)0; /* failure */
183    else
184        return (Status)1; /* success */
185}
186
187Xauth *
188XSecurityAllocXauth(void)
189{
190    return Xcalloc(1, sizeof(Xauth));
191}
192
193void
194XSecurityFreeXauth(Xauth *auth)
195{
196    XFree(auth);
197}
198
199#ifdef HAVE___BUILTIN_POPCOUNTL
200# define Ones __builtin_popcountl
201#else
202/*
203 * Count the number of bits set to 1 in a 32-bit word.
204 * Algorithm from MIT AI Lab Memo 239: "HAKMEM", ITEM 169.
205 * http://dspace.mit.edu/handle/1721.1/6086
206 */
207static inline int
208Ones(Mask mask)
209{
210    register Mask y;
211
212    y = (mask >> 1) & 033333333333;
213    y = mask - y - ((y >>1) & 033333333333);
214    return (((y + (y >> 3)) & 030707070707) % 077);
215}
216#endif
217
218Xauth *
219XSecurityGenerateAuthorization(
220    Display *dpy,
221    Xauth *auth_in,
222    unsigned long valuemask,
223    XSecurityAuthorizationAttributes *attributes,
224    XSecurityAuthorization *auth_id_return)
225{
226    XExtDisplayInfo *info = find_display (dpy);
227    register xSecurityGenerateAuthorizationReq *req;
228    xSecurityGenerateAuthorizationReply rep;
229    Xauth *auth_return;
230    unsigned long values[4];
231    unsigned long *value = values;
232    unsigned int nvalues;
233
234    /* values array must have a slot for each possible valuemask value */
235    assert(Ones(XSecurityAllAuthorizationAttributes)
236           == (sizeof(values) / sizeof(values[0])));
237
238    *auth_id_return = 0;  /* in case we fail */
239
240    /* make sure extension is available */
241
242    SecurityCheckExtension (dpy, info, (Xauth *)NULL);
243
244    LockDisplay(dpy);
245    SecurityGetReq(SecurityGenerateAuthorization, req, info);
246
247    req->nbytesAuthProto = auth_in->name_length;
248    req->nbytesAuthData  = auth_in->data_length;
249
250    /* adjust length to account for auth name and data */
251    req->length += (auth_in->name_length + (unsigned)3) >> 2;
252    req->length += (auth_in->data_length + (unsigned)3) >> 2;
253
254    /* adjust length to account for list of values */
255    req->valueMask = valuemask & XSecurityAllAuthorizationAttributes;
256    nvalues = Ones(req->valueMask);
257    req->length += nvalues;
258
259    /* send auth name and data */
260    Data(dpy, auth_in->name, auth_in->name_length);
261    Data(dpy, auth_in->data, auth_in->data_length);
262
263    /* send values */
264    if (valuemask & XSecurityTimeout)	 *value++ = attributes->timeout;
265    if (valuemask & XSecurityTrustLevel) *value++ = attributes->trust_level;
266    if (valuemask & XSecurityGroup)	 *value++ = attributes->group;
267    if (valuemask & XSecurityEventMask)	 *value++ = attributes->event_mask;
268
269    nvalues <<= 2;
270    Data32(dpy, (long *)values, (long)nvalues);
271
272    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) {
273	UnlockDisplay (dpy);
274	SyncHandle ();
275	return (Xauth *)NULL;
276    }
277
278    *auth_id_return = rep.authId;
279
280    /* Allocate space for the Xauth struct and the auth name and data all
281     * in one hunk.  This lets XSecurityFreeXauth not have to care
282     * about whether the auth was allocated here or in
283     * XSecurityAllocXauth; in both cases, you just free one pointer.
284     */
285
286    if ((auth_return = (Xauth *)Xcalloc(1,
287		(sizeof(Xauth) + auth_in->name_length + rep.dataLength))))
288    {
289	auth_return->data_length = rep.dataLength;
290	auth_return->data = (char *)&auth_return[1];
291	_XReadPad(dpy, auth_return->data, (long)rep.dataLength);
292
293	auth_return->name_length = auth_in->name_length;
294	auth_return->name = auth_return->data + auth_return->data_length;
295	memcpy(auth_return->name, auth_in->name, auth_return->name_length);
296    }
297    else
298    {
299	_XEatDataWords(dpy, rep.length);
300    }
301
302    UnlockDisplay (dpy);
303    SyncHandle ();
304    return auth_return;
305
306} /* XSecurityGenerateAuthorization */
307
308Status
309XSecurityRevokeAuthorization(
310    Display *dpy,
311    XSecurityAuthorization auth_id)
312{
313    XExtDisplayInfo *info = find_display (dpy);
314    xSecurityRevokeAuthorizationReq *req;
315
316    SecurityCheckExtension (dpy, info, 0);
317    LockDisplay(dpy);
318    SecurityGetReq(SecurityRevokeAuthorization, req, info);
319    req->authId = auth_id;
320    UnlockDisplay (dpy);
321    SyncHandle ();
322    return 1;
323} /* XSecurityRevokeAuthorization */
324