extension.c revision 9ace9065
1/***********************************************************
2
3Copyright 1987, 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
26Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
27
28                        All Rights Reserved
29
30Permission to use, copy, modify, and distribute this software and its
31documentation for any purpose and without fee is hereby granted,
32provided that the above copyright notice appear in all copies and that
33both that copyright notice and this permission notice appear in
34supporting documentation, and that the name of Digital not be
35used in advertising or publicity pertaining to distribution of the
36software without specific, written prior permission.
37
38DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44SOFTWARE.
45
46******************************************************************/
47
48#ifdef HAVE_DIX_CONFIG_H
49#include <dix-config.h>
50#endif
51
52#include <X11/X.h>
53#include <X11/Xproto.h>
54#include "misc.h"
55#include "dixstruct.h"
56#include "extnsionst.h"
57#include "gcstruct.h"
58#include "scrnintstr.h"
59#include "dispatch.h"
60#include "privates.h"
61#include "registry.h"
62#include "xace.h"
63
64#define LAST_EVENT  128
65#define LAST_ERROR 255
66
67static ExtensionEntry **extensions = (ExtensionEntry **)NULL;
68
69int lastEvent = EXTENSION_EVENT_BASE;
70static int lastError = FirstExtensionError;
71static unsigned int NumExtensions = 0;
72
73ExtensionEntry *
74AddExtension(char *name, int NumEvents, int NumErrors,
75	     int (*MainProc)(ClientPtr c1),
76	     int (*SwappedMainProc)(ClientPtr c2),
77	     void (*CloseDownProc)(ExtensionEntry *e),
78	     unsigned short (*MinorOpcodeProc)(ClientPtr c3))
79{
80    int i;
81    ExtensionEntry *ext, **newexts;
82
83    if (!MainProc || !SwappedMainProc || !MinorOpcodeProc)
84        return((ExtensionEntry *) NULL);
85    if ((lastEvent + NumEvents > LAST_EVENT) ||
86	        (unsigned)(lastError + NumErrors > LAST_ERROR)) {
87        LogMessage(X_ERROR, "Not enabling extension %s: maximum number of "
88                   "events or errors exceeded.\n", name);
89        return((ExtensionEntry *) NULL);
90    }
91
92    ext = calloc(sizeof (ExtensionEntry), 1);
93    if (!ext)
94	return NULL;
95    if (!dixAllocatePrivates(&ext->devPrivates, PRIVATE_EXTENSION)) {
96	free(ext);
97	return NULL;
98    }
99    ext->name = strdup(name);
100    ext->num_aliases = 0;
101    ext->aliases = (char **)NULL;
102    if (!ext->name)
103    {
104	dixFreePrivates(ext->devPrivates, PRIVATE_EXTENSION);
105	free(ext);
106	return((ExtensionEntry *) NULL);
107    }
108    i = NumExtensions;
109    newexts = (ExtensionEntry **) realloc(extensions,
110					   (i + 1) * sizeof(ExtensionEntry *));
111    if (!newexts)
112    {
113	free(ext->name);
114	dixFreePrivates(ext->devPrivates, PRIVATE_EXTENSION);
115	free(ext);
116	return((ExtensionEntry *) NULL);
117    }
118    NumExtensions++;
119    extensions = newexts;
120    extensions[i] = ext;
121    ext->index = i;
122    ext->base = i + EXTENSION_BASE;
123    ext->CloseDown = CloseDownProc;
124    ext->MinorOpcode = MinorOpcodeProc;
125    ProcVector[i + EXTENSION_BASE] = MainProc;
126    SwappedProcVector[i + EXTENSION_BASE] = SwappedMainProc;
127    if (NumEvents)
128    {
129        ext->eventBase = lastEvent;
130	ext->eventLast = lastEvent + NumEvents;
131	lastEvent += NumEvents;
132    }
133    else
134    {
135        ext->eventBase = 0;
136        ext->eventLast = 0;
137    }
138    if (NumErrors)
139    {
140        ext->errorBase = lastError;
141	ext->errorLast = lastError + NumErrors;
142	lastError += NumErrors;
143    }
144    else
145    {
146        ext->errorBase = 0;
147        ext->errorLast = 0;
148    }
149
150    RegisterExtensionNames(ext);
151    return ext;
152}
153
154Bool AddExtensionAlias(char *alias, ExtensionEntry *ext)
155{
156    char *name;
157    char **aliases;
158
159    if (!ext)
160        return FALSE ;
161    aliases = (char **)realloc(ext->aliases,
162				(ext->num_aliases + 1) * sizeof(char *));
163    if (!aliases)
164	return FALSE;
165    ext->aliases = aliases;
166    name = strdup(alias);
167    if (!name)
168	return FALSE;
169    ext->aliases[ext->num_aliases] = name;
170    ext->num_aliases++;
171    return TRUE;
172}
173
174static int
175FindExtension(char *extname, int len)
176{
177    int i, j;
178
179    for (i=0; i<NumExtensions; i++)
180    {
181	if ((strlen(extensions[i]->name) == len) &&
182	    !strncmp(extname, extensions[i]->name, len))
183	    break;
184	for (j = extensions[i]->num_aliases; --j >= 0;)
185	{
186	    if ((strlen(extensions[i]->aliases[j]) == len) &&
187		!strncmp(extname, extensions[i]->aliases[j], len))
188		break;
189	}
190	if (j >= 0) break;
191    }
192    return ((i == NumExtensions) ? -1 : i);
193}
194
195/*
196 * CheckExtension returns the extensions[] entry for the requested
197 * extension name.  Maybe this could just return a Bool instead?
198 */
199ExtensionEntry *
200CheckExtension(const char *extname)
201{
202    int n;
203
204    n = FindExtension((char*)extname, strlen(extname));
205    if (n != -1)
206	return extensions[n];
207    else
208	return NULL;
209}
210
211/*
212 * Added as part of Xace.
213 */
214ExtensionEntry *
215GetExtensionEntry(int major)
216{
217    if (major < EXTENSION_BASE)
218	return NULL;
219    major -= EXTENSION_BASE;
220    if (major >= NumExtensions)
221	return NULL;
222    return extensions[major];
223}
224
225unsigned short
226StandardMinorOpcode(ClientPtr client)
227{
228    return ((xReq *)client->requestBuffer)->data;
229}
230
231unsigned short
232MinorOpcodeOfRequest(ClientPtr client)
233{
234    unsigned char major;
235
236    major = ((xReq *)client->requestBuffer)->reqType;
237    if (major < EXTENSION_BASE)
238	return 0;
239    major -= EXTENSION_BASE;
240    if (major >= NumExtensions)
241	return 0;
242    return (*extensions[major]->MinorOpcode)(client);
243}
244
245void
246CloseDownExtensions(void)
247{
248    int i,j;
249
250    for (i = NumExtensions - 1; i >= 0; i--)
251    {
252	if (extensions[i]->CloseDown)
253	    extensions[i]->CloseDown(extensions[i]);
254	NumExtensions = i;
255	free(extensions[i]->name);
256	for (j = extensions[i]->num_aliases; --j >= 0;)
257	    free(extensions[i]->aliases[j]);
258	free(extensions[i]->aliases);
259	dixFreePrivates(extensions[i]->devPrivates, PRIVATE_EXTENSION);
260	free(extensions[i]);
261    }
262    free(extensions);
263    extensions = (ExtensionEntry **)NULL;
264    lastEvent = EXTENSION_EVENT_BASE;
265    lastError = FirstExtensionError;
266}
267
268int
269ProcQueryExtension(ClientPtr client)
270{
271    xQueryExtensionReply reply;
272    int i;
273    REQUEST(xQueryExtensionReq);
274
275    REQUEST_FIXED_SIZE(xQueryExtensionReq, stuff->nbytes);
276
277    memset(&reply, 0, sizeof(xQueryExtensionReply));
278    reply.type = X_Reply;
279    reply.length = 0;
280    reply.major_opcode = 0;
281    reply.sequenceNumber = client->sequence;
282
283    if ( ! NumExtensions )
284        reply.present = xFalse;
285    else
286    {
287	i = FindExtension((char *)&stuff[1], stuff->nbytes);
288        if (i < 0 || XaceHook(XACE_EXT_ACCESS, client, extensions[i]))
289            reply.present = xFalse;
290        else
291        {
292            reply.present = xTrue;
293	    reply.major_opcode = extensions[i]->base;
294	    reply.first_event = extensions[i]->eventBase;
295	    reply.first_error = extensions[i]->errorBase;
296	}
297    }
298    WriteReplyToClient(client, sizeof(xQueryExtensionReply), &reply);
299    return Success;
300}
301
302int
303ProcListExtensions(ClientPtr client)
304{
305    xListExtensionsReply reply;
306    char *bufptr, *buffer;
307    int total_length = 0;
308
309    REQUEST_SIZE_MATCH(xReq);
310
311    memset(&reply, 0, sizeof(xListExtensionsReply));
312    reply.type = X_Reply;
313    reply.nExtensions = 0;
314    reply.length = 0;
315    reply.sequenceNumber = client->sequence;
316    buffer = NULL;
317
318    if ( NumExtensions )
319    {
320        int i, j;
321
322        for (i=0;  i<NumExtensions; i++)
323	{
324	    /* call callbacks to find out whether to show extension */
325	    if (XaceHook(XACE_EXT_ACCESS, client, extensions[i]) != Success)
326		continue;
327
328	    total_length += strlen(extensions[i]->name) + 1;
329	    reply.nExtensions += 1 + extensions[i]->num_aliases;
330	    for (j = extensions[i]->num_aliases; --j >= 0;)
331		total_length += strlen(extensions[i]->aliases[j]) + 1;
332	}
333        reply.length = bytes_to_int32(total_length);
334	buffer = bufptr = malloc(total_length);
335	if (!buffer)
336	    return BadAlloc;
337        for (i=0;  i<NumExtensions; i++)
338        {
339	    int len;
340	    if (XaceHook(XACE_EXT_ACCESS, client, extensions[i]) != Success)
341		continue;
342
343            *bufptr++ = len = strlen(extensions[i]->name);
344	    memmove(bufptr, extensions[i]->name,  len);
345	    bufptr += len;
346	    for (j = extensions[i]->num_aliases; --j >= 0;)
347	    {
348		*bufptr++ = len = strlen(extensions[i]->aliases[j]);
349		memmove(bufptr, extensions[i]->aliases[j],  len);
350		bufptr += len;
351	    }
352	}
353    }
354    WriteReplyToClient(client, sizeof(xListExtensionsReply), &reply);
355    if (reply.length)
356        WriteToClient(client, total_length, buffer);
357
358    free(buffer);
359    return Success;
360}
361