1 /*
2
3 Copyright 1988, 1998 The Open Group
4
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of The Open Group shall
23 not be used in advertising or otherwise to promote the sale, use or
24 other dealings in this Software without prior written authorization
25 from The Open Group.
26
27 */
28
29 /*
30 * authorization hooks for the server
31 * Author: Keith Packard, MIT X Consortium
32 */
33
34 #ifdef HAVE_DIX_CONFIG_H
35 #include <dix-config.h>
36 #endif
37
38 #include <X11/X.h>
39 #include <X11/Xauth.h>
40 #include "misc.h"
41 #include "osdep.h"
42 #include "dixstruct.h"
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <errno.h>
46 #ifdef WIN32
47 #include <X11/Xw32defs.h>
48 #endif
49 #ifdef HAVE_LIBBSD
50 #include <bsd/stdlib.h> /* for arc4random_buf() */
51 #endif
52
53 struct protocol {
54 unsigned short name_length;
55 const char *name;
56 AuthAddCFunc Add; /* new authorization data */
57 AuthCheckFunc Check; /* verify client authorization data */
58 AuthRstCFunc Reset; /* delete all authorization data entries */
59 AuthFromIDFunc FromID; /* convert ID to cookie */
60 AuthRemCFunc Remove; /* remove a specific cookie */
61 #ifdef XCSECURITY
62 AuthGenCFunc Generate;
63 #endif
64 };
65
66 static struct protocol protocols[] = {
67 {(unsigned short) 18, "MIT-MAGIC-COOKIE-1",
68 MitAddCookie, MitCheckCookie, MitResetCookie,
69 MitFromID, MitRemoveCookie,
70 #ifdef XCSECURITY
71 MitGenerateCookie
72 #endif
73 },
74 #ifdef HASXDMAUTH
75 {(unsigned short) 19, "XDM-AUTHORIZATION-1",
76 XdmAddCookie, XdmCheckCookie, XdmResetCookie,
77 XdmFromID, XdmRemoveCookie,
78 #ifdef XCSECURITY
79 NULL
80 #endif
81 },
82 #endif
83 #ifdef SECURE_RPC
84 {(unsigned short) 9, "SUN-DES-1",
85 SecureRPCAdd, SecureRPCCheck, SecureRPCReset,
86 SecureRPCFromID, SecureRPCRemove,
87 #ifdef XCSECURITY
88 NULL
89 #endif
90 },
91 #endif
92 };
93
94 #define NUM_AUTHORIZATION ARRAY_SIZE(protocols)
95
96 /*
97 * Initialize all classes of authorization by reading the
98 * specified authorization file
99 */
100
101 static const char *authorization_file = NULL;
102
103 static Bool ShouldLoadAuth = TRUE;
104
105 void
InitAuthorization(const char * file_name)106 InitAuthorization(const char *file_name)
107 {
108 authorization_file = file_name;
109 }
110
111 static int
LoadAuthorization(void)112 LoadAuthorization(void)
113 {
114 FILE *f;
115 Xauth *auth;
116 int i;
117 int count = 0;
118
119 ShouldLoadAuth = FALSE;
120 if (!authorization_file)
121 return 0;
122
123 errno = 0;
124 f = Fopen(authorization_file, "r");
125 if (!f) {
126 LogMessageVerb(X_ERROR, 0,
127 "Failed to open authorization file \"%s\": %s\n",
128 authorization_file,
129 errno != 0 ? strerror(errno) : "Unknown error");
130 return -1;
131 }
132
133 while ((auth = XauReadAuth(f)) != 0) {
134 for (i = 0; i < NUM_AUTHORIZATION; i++) {
135 if (protocols[i].name_length == auth->name_length &&
136 memcmp(protocols[i].name, auth->name,
137 (int) auth->name_length) == 0 && protocols[i].Add) {
138 ++count;
139 (*protocols[i].Add) (auth->data_length, auth->data,
140 FakeClientID(0));
141 }
142 }
143 XauDisposeAuth(auth);
144 }
145
146 Fclose(f);
147 return count;
148 }
149
150 #ifdef XDMCP
151 /*
152 * XdmcpInit calls this function to discover all authorization
153 * schemes supported by the display
154 */
155 void
RegisterAuthorizations(void)156 RegisterAuthorizations(void)
157 {
158 int i;
159
160 for (i = 0; i < NUM_AUTHORIZATION; i++)
161 XdmcpRegisterAuthorization(protocols[i].name,
162 (int) protocols[i].name_length);
163 }
164 #endif
165
166 XID
CheckAuthorization(unsigned int name_length,const char * name,unsigned int data_length,const char * data,ClientPtr client,const char ** reason)167 CheckAuthorization(unsigned int name_length,
168 const char *name,
169 unsigned int data_length,
170 const char *data, ClientPtr client, const char **reason)
171 { /* failure message. NULL for default msg */
172 int i;
173 struct stat buf;
174 static time_t lastmod = 0;
175 static Bool loaded = FALSE;
176
177 if (!authorization_file || stat(authorization_file, &buf)) {
178 if (lastmod != 0) {
179 lastmod = 0;
180 ShouldLoadAuth = TRUE; /* stat lost, so force reload */
181 }
182 }
183 else if (buf.st_mtime > lastmod) {
184 lastmod = buf.st_mtime;
185 ShouldLoadAuth = TRUE;
186 }
187 if (ShouldLoadAuth) {
188 int loadauth = LoadAuthorization();
189
190 /*
191 * If the authorization file has at least one entry for this server,
192 * disable local access. (loadauth > 0)
193 *
194 * If there are zero entries (either initially or when the
195 * authorization file is later reloaded), or if a valid
196 * authorization file was never loaded, enable local access.
197 * (loadauth == 0 || !loaded)
198 *
199 * If the authorization file was loaded initially (with valid
200 * entries for this server), and reloading it later fails, don't
201 * change anything. (loadauth == -1 && loaded)
202 */
203
204 if (loadauth > 0) {
205 DisableLocalAccess(); /* got at least one */
206 loaded = TRUE;
207 }
208 else if (loadauth == 0 || !loaded)
209 EnableLocalAccess();
210 }
211 if (name_length) {
212 for (i = 0; i < NUM_AUTHORIZATION; i++) {
213 if (protocols[i].name_length == name_length &&
214 memcmp(protocols[i].name, name, (int) name_length) == 0) {
215 return (*protocols[i].Check) (data_length, data, client,
216 reason);
217 }
218 *reason = "Protocol not supported by server\n";
219 }
220 }
221 else
222 *reason = "No protocol specified\n";
223 return (XID) ~0L;
224 }
225
226 void
ResetAuthorization(void)227 ResetAuthorization(void)
228 {
229 int i;
230
231 for (i = 0; i < NUM_AUTHORIZATION; i++)
232 if (protocols[i].Reset)
233 (*protocols[i].Reset) ();
234 ShouldLoadAuth = TRUE;
235 }
236
237 int
AuthorizationFromID(XID id,unsigned short * name_lenp,const char ** namep,unsigned short * data_lenp,char ** datap)238 AuthorizationFromID(XID id,
239 unsigned short *name_lenp,
240 const char **namep, unsigned short *data_lenp, char **datap)
241 {
242 int i;
243
244 for (i = 0; i < NUM_AUTHORIZATION; i++) {
245 if (protocols[i].FromID &&
246 (*protocols[i].FromID) (id, data_lenp, datap)) {
247 *name_lenp = protocols[i].name_length;
248 *namep = protocols[i].name;
249 return 1;
250 }
251 }
252 return 0;
253 }
254
255 int
RemoveAuthorization(unsigned short name_length,const char * name,unsigned short data_length,const char * data)256 RemoveAuthorization(unsigned short name_length,
257 const char *name,
258 unsigned short data_length, const char *data)
259 {
260 int i;
261
262 for (i = 0; i < NUM_AUTHORIZATION; i++) {
263 if (protocols[i].name_length == name_length &&
264 memcmp(protocols[i].name, name, (int) name_length) == 0 &&
265 protocols[i].Remove) {
266 return (*protocols[i].Remove) (data_length, data);
267 }
268 }
269 return 0;
270 }
271
272 int
AddAuthorization(unsigned name_length,const char * name,unsigned data_length,char * data)273 AddAuthorization(unsigned name_length, const char *name,
274 unsigned data_length, char *data)
275 {
276 int i;
277
278 for (i = 0; i < NUM_AUTHORIZATION; i++) {
279 if (protocols[i].name_length == name_length &&
280 memcmp(protocols[i].name, name, (int) name_length) == 0 &&
281 protocols[i].Add) {
282 return (*protocols[i].Add) (data_length, data, FakeClientID(0));
283 }
284 }
285 return 0;
286 }
287
288 #ifdef XCSECURITY
289
290 XID
GenerateAuthorization(unsigned name_length,const char * name,unsigned data_length,const char * data,unsigned * data_length_return,char ** data_return)291 GenerateAuthorization(unsigned name_length,
292 const char *name,
293 unsigned data_length,
294 const char *data,
295 unsigned *data_length_return, char **data_return)
296 {
297 int i;
298
299 for (i = 0; i < NUM_AUTHORIZATION; i++) {
300 if (protocols[i].name_length == name_length &&
301 memcmp(protocols[i].name, name, (int) name_length) == 0 &&
302 protocols[i].Generate) {
303 return (*protocols[i].Generate) (data_length, data,
304 FakeClientID(0),
305 data_length_return, data_return);
306 }
307 }
308 return -1;
309 }
310
311 #endif /* XCSECURITY */
312
313 void
GenerateRandomData(int len,char * buf)314 GenerateRandomData(int len, char *buf)
315 {
316 #ifdef HAVE_ARC4RANDOM_BUF
317 arc4random_buf(buf, len);
318 #else
319 int fd;
320
321 fd = open("/dev/urandom", O_RDONLY);
322 read(fd, buf, len);
323 close(fd);
324 #endif
325 }
326