1 /************************************************************
2 
3 Author: Eamon Walsh <ewalsh@tycho.nsa.gov>
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 this permission notice appear in supporting documentation.  This permission
8 notice shall be included in all copies or substantial portions of the
9 Software.
10 
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
14 AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
15 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
16 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17 
18 ********************************************************/
19 
20 #ifdef HAVE_DIX_CONFIG_H
21 #include <dix-config.h>
22 #endif
23 
24 #include <stdlib.h>
25 #include <string.h>
26 #include <X11/X.h>
27 #include <X11/Xproto.h>
28 #include "resource.h"
29 #include "registry.h"
30 
31 #define BASE_SIZE 16
32 
33 #ifdef X_REGISTRY_REQUEST
34 #define CORE "X11"
35 #define FILENAME SERVER_MISC_CONFIG_PATH "/protocol.txt"
36 
37 #define PROT_COMMENT '#'
38 #define PROT_REQUEST 'R'
39 #define PROT_EVENT 'V'
40 #define PROT_ERROR 'E'
41 
42 static FILE *fh;
43 
44 static char ***requests, **events, **errors;
45 static unsigned nmajor, *nminor, nevent, nerror;
46 #endif
47 
48 #ifdef X_REGISTRY_RESOURCE
49 static const char **resources;
50 static unsigned nresource;
51 #endif
52 
53 #if defined(X_REGISTRY_RESOURCE) || defined(X_REGISTRY_REQUEST)
54 /*
55  * File parsing routines
56  */
57 static int
double_size(void * p,unsigned n,unsigned size)58 double_size(void *p, unsigned n, unsigned size)
59 {
60     char **ptr = (char **) p;
61     unsigned s, f;
62 
63     if (n) {
64         s = n * size;
65         n *= 2 * size;
66         f = n;
67     }
68     else {
69         s = 0;
70         n = f = BASE_SIZE * size;
71     }
72 
73     *ptr = realloc(*ptr, n);
74     if (!*ptr) {
75         dixResetRegistry();
76         return FALSE;
77     }
78     memset(*ptr + s, 0, f - s);
79     return TRUE;
80 }
81 #endif
82 
83 #ifdef X_REGISTRY_REQUEST
84 /*
85  * Request/event/error registry functions
86  */
87 static void
RegisterRequestName(unsigned major,unsigned minor,char * name)88 RegisterRequestName(unsigned major, unsigned minor, char *name)
89 {
90     while (major >= nmajor) {
91         if (!double_size(&requests, nmajor, sizeof(char **)))
92             return;
93         if (!double_size(&nminor, nmajor, sizeof(unsigned)))
94             return;
95         nmajor = nmajor ? nmajor * 2 : BASE_SIZE;
96     }
97     while (minor >= nminor[major]) {
98         if (!double_size(requests + major, nminor[major], sizeof(char *)))
99             return;
100         nminor[major] = nminor[major] ? nminor[major] * 2 : BASE_SIZE;
101     }
102 
103     free(requests[major][minor]);
104     requests[major][minor] = name;
105 }
106 
107 static void
RegisterEventName(unsigned event,char * name)108 RegisterEventName(unsigned event, char *name)
109 {
110     while (event >= nevent) {
111         if (!double_size(&events, nevent, sizeof(char *)))
112             return;
113         nevent = nevent ? nevent * 2 : BASE_SIZE;
114     }
115 
116     free(events[event]);
117     events[event] = name;
118 }
119 
120 static void
RegisterErrorName(unsigned error,char * name)121 RegisterErrorName(unsigned error, char *name)
122 {
123     while (error >= nerror) {
124         if (!double_size(&errors, nerror, sizeof(char *)))
125             return;
126         nerror = nerror ? nerror * 2 : BASE_SIZE;
127     }
128 
129     free(errors[error]);
130     errors[error] = name;
131 }
132 
133 void
RegisterExtensionNames(ExtensionEntry * extEntry)134 RegisterExtensionNames(ExtensionEntry * extEntry)
135 {
136     char buf[256], *lineobj, *ptr;
137     unsigned offset;
138 
139     if (fh == NULL)
140         return;
141 
142     rewind(fh);
143 
144     while (fgets(buf, sizeof(buf), fh)) {
145         lineobj = NULL;
146         ptr = strchr(buf, '\n');
147         if (ptr)
148             *ptr = 0;
149 
150         /* Check for comments or empty lines */
151         switch (buf[0]) {
152         case PROT_REQUEST:
153         case PROT_EVENT:
154         case PROT_ERROR:
155             break;
156         case PROT_COMMENT:
157         case '\0':
158             continue;
159         default:
160             goto invalid;
161         }
162 
163         /* Check for space character in the fifth position */
164         ptr = strchr(buf, ' ');
165         if (!ptr || ptr != buf + 4)
166             goto invalid;
167 
168         /* Duplicate the string after the space */
169         lineobj = strdup(ptr + 1);
170         if (!lineobj)
171             continue;
172 
173         /* Check for a colon somewhere on the line */
174         ptr = strchr(buf, ':');
175         if (!ptr)
176             goto invalid;
177 
178         /* Compare the part before colon with the target extension name */
179         *ptr = 0;
180         if (strcmp(buf + 5, extEntry->name))
181             goto skip;
182 
183         /* Get the opcode for the request, event, or error */
184         offset = strtol(buf + 1, &ptr, 10);
185         if (offset == 0 && ptr == buf + 1)
186             goto invalid;
187 
188         /* Save the strdup result in the registry */
189         switch (buf[0]) {
190         case PROT_REQUEST:
191             if (extEntry->base)
192                 RegisterRequestName(extEntry->base, offset, lineobj);
193             else
194                 RegisterRequestName(offset, 0, lineobj);
195             continue;
196         case PROT_EVENT:
197             RegisterEventName(extEntry->eventBase + offset, lineobj);
198             continue;
199         case PROT_ERROR:
200             RegisterErrorName(extEntry->errorBase + offset, lineobj);
201             continue;
202         }
203 
204  invalid:
205         LogMessage(X_WARNING, "Invalid line in " FILENAME ", skipping\n");
206  skip:
207         free(lineobj);
208     }
209 }
210 
211 const char *
LookupRequestName(int major,int minor)212 LookupRequestName(int major, int minor)
213 {
214     if (major >= nmajor)
215         return XREGISTRY_UNKNOWN;
216     if (minor >= nminor[major])
217         return XREGISTRY_UNKNOWN;
218 
219     return requests[major][minor] ? requests[major][minor] : XREGISTRY_UNKNOWN;
220 }
221 
222 const char *
LookupMajorName(int major)223 LookupMajorName(int major)
224 {
225     if (major < 128) {
226         const char *retval;
227 
228         if (major >= nmajor)
229             return XREGISTRY_UNKNOWN;
230         if (0 >= nminor[major])
231             return XREGISTRY_UNKNOWN;
232 
233         retval = requests[major][0];
234         return retval ? retval + sizeof(CORE) : XREGISTRY_UNKNOWN;
235     }
236     else {
237         ExtensionEntry *extEntry = GetExtensionEntry(major);
238 
239         return extEntry ? extEntry->name : XREGISTRY_UNKNOWN;
240     }
241 }
242 
243 const char *
LookupEventName(int event)244 LookupEventName(int event)
245 {
246     event &= 127;
247     if (event >= nevent)
248         return XREGISTRY_UNKNOWN;
249 
250     return events[event] ? events[event] : XREGISTRY_UNKNOWN;
251 }
252 
253 const char *
LookupErrorName(int error)254 LookupErrorName(int error)
255 {
256     if (error >= nerror)
257         return XREGISTRY_UNKNOWN;
258 
259     return errors[error] ? errors[error] : XREGISTRY_UNKNOWN;
260 }
261 #endif /* X_REGISTRY_REQUEST */
262 
263 #ifdef X_REGISTRY_RESOURCE
264 /*
265  * Resource registry functions
266  */
267 
268 void
RegisterResourceName(RESTYPE resource,const char * name)269 RegisterResourceName(RESTYPE resource, const char *name)
270 {
271     resource &= TypeMask;
272 
273     while (resource >= nresource) {
274         if (!double_size(&resources, nresource, sizeof(char *)))
275             return;
276         nresource = nresource ? nresource * 2 : BASE_SIZE;
277     }
278 
279     resources[resource] = name;
280 }
281 
282 const char *
LookupResourceName(RESTYPE resource)283 LookupResourceName(RESTYPE resource)
284 {
285     resource &= TypeMask;
286     if (resource >= nresource)
287         return XREGISTRY_UNKNOWN;
288 
289     return resources[resource] ? resources[resource] : XREGISTRY_UNKNOWN;
290 }
291 #endif /* X_REGISTRY_RESOURCE */
292 
293 void
dixFreeRegistry(void)294 dixFreeRegistry(void)
295 {
296 #ifdef X_REGISTRY_REQUEST
297     /* Free all memory */
298     while (nmajor--) {
299         while (nminor[nmajor])
300             free(requests[nmajor][--nminor[nmajor]]);
301         free(requests[nmajor]);
302     }
303     free(requests);
304     free(nminor);
305 
306     while (nevent--)
307         free(events[nevent]);
308     free(events);
309 
310     while (nerror--)
311         free(errors[nerror]);
312     free(errors);
313     requests = NULL;
314     nminor = NULL;
315     events = NULL;
316     errors = NULL;
317     nmajor = nevent = nerror = 0;
318 #endif
319 
320 #ifdef X_REGISTRY_RESOURCE
321     free(resources);
322 
323     resources = NULL;
324     nresource = 0;
325 #endif
326 }
327 
328 void
dixCloseRegistry(void)329 dixCloseRegistry(void)
330 {
331 #ifdef X_REGISTRY_REQUEST
332     if (fh) {
333 	fclose(fh);
334         fh = NULL;
335     }
336 #endif
337 }
338 
339 /*
340  * Setup and teardown
341  */
342 void
dixResetRegistry(void)343 dixResetRegistry(void)
344 {
345 #ifdef X_REGISTRY_REQUEST
346     ExtensionEntry extEntry = { .name = CORE };
347 #endif
348 
349     dixFreeRegistry();
350 
351 #ifdef X_REGISTRY_REQUEST
352     /* Open the protocol file */
353     fh = fopen(FILENAME, "r");
354     if (!fh)
355         LogMessage(X_WARNING,
356                    "Failed to open protocol names file " FILENAME "\n");
357 
358     /* Add the core protocol */
359     RegisterExtensionNames(&extEntry);
360 #endif
361 
362 #ifdef X_REGISTRY_RESOURCE
363     /* Add built-in resources */
364     RegisterResourceName(RT_NONE, "NONE");
365     RegisterResourceName(RT_WINDOW, "WINDOW");
366     RegisterResourceName(RT_PIXMAP, "PIXMAP");
367     RegisterResourceName(RT_GC, "GC");
368     RegisterResourceName(RT_FONT, "FONT");
369     RegisterResourceName(RT_CURSOR, "CURSOR");
370     RegisterResourceName(RT_COLORMAP, "COLORMAP");
371     RegisterResourceName(RT_CMAPENTRY, "COLORMAP ENTRY");
372     RegisterResourceName(RT_OTHERCLIENT, "OTHER CLIENT");
373     RegisterResourceName(RT_PASSIVEGRAB, "PASSIVE GRAB");
374 #endif
375 }
376