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