extension.c revision 05b261ec
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#define NEED_EVENTS
54#define NEED_REPLIES
55#include <X11/Xproto.h>
56#include "misc.h"
57#include "dixstruct.h"
58#include "extnsionst.h"
59#include "gcstruct.h"
60#include "scrnintstr.h"
61#include "dispatch.h"
62#include "xace.h"
63
64#define EXTENSION_BASE  128
65#define EXTENSION_EVENT_BASE  64
66#define LAST_EVENT  128
67#define LAST_ERROR 255
68
69static ExtensionEntry **extensions = (ExtensionEntry **)NULL;
70
71int lastEvent = EXTENSION_EVENT_BASE;
72static int lastError = FirstExtensionError;
73static unsigned int NumExtensions = 0;
74
75extern int extensionPrivateLen;
76extern unsigned *extensionPrivateSizes;
77extern unsigned totalExtensionSize;
78
79static void
80InitExtensionPrivates(ExtensionEntry *ext)
81{
82    char *ptr;
83    DevUnion *ppriv;
84    unsigned *sizes;
85    unsigned size;
86    int i;
87
88    if (totalExtensionSize == sizeof(ExtensionEntry))
89	ppriv = (DevUnion *)NULL;
90    else
91	ppriv = (DevUnion *)(ext + 1);
92
93    ext->devPrivates = ppriv;
94    sizes = extensionPrivateSizes;
95    ptr = (char *)(ppriv + extensionPrivateLen);
96    for (i = extensionPrivateLen; --i >= 0; ppriv++, sizes++)
97    {
98	if ( (size = *sizes) )
99	{
100	    ppriv->ptr = (pointer)ptr;
101	    ptr += size;
102	}
103	else
104	    ppriv->ptr = (pointer)NULL;
105    }
106}
107
108_X_EXPORT ExtensionEntry *
109AddExtension(char *name, int NumEvents, int NumErrors,
110	     int (*MainProc)(ClientPtr c1),
111	     int (*SwappedMainProc)(ClientPtr c2),
112	     void (*CloseDownProc)(ExtensionEntry *e),
113	     unsigned short (*MinorOpcodeProc)(ClientPtr c3))
114{
115    int i;
116    ExtensionEntry *ext, **newexts;
117
118    if (!MainProc || !SwappedMainProc || !CloseDownProc || !MinorOpcodeProc)
119        return((ExtensionEntry *) NULL);
120    if ((lastEvent + NumEvents > LAST_EVENT) ||
121	        (unsigned)(lastError + NumErrors > LAST_ERROR))
122        return((ExtensionEntry *) NULL);
123
124    ext = (ExtensionEntry *) xalloc(totalExtensionSize);
125    if (!ext)
126	return((ExtensionEntry *) NULL);
127    bzero(ext, totalExtensionSize);
128    InitExtensionPrivates(ext);
129    ext->name = (char *)xalloc(strlen(name) + 1);
130    ext->num_aliases = 0;
131    ext->aliases = (char **)NULL;
132    if (!ext->name)
133    {
134	xfree(ext);
135	return((ExtensionEntry *) NULL);
136    }
137    strcpy(ext->name,  name);
138    i = NumExtensions;
139    newexts = (ExtensionEntry **) xrealloc(extensions,
140					   (i + 1) * sizeof(ExtensionEntry *));
141    if (!newexts)
142    {
143	xfree(ext->name);
144	xfree(ext);
145	return((ExtensionEntry *) NULL);
146    }
147    NumExtensions++;
148    extensions = newexts;
149    extensions[i] = ext;
150    ext->index = i;
151    ext->base = i + EXTENSION_BASE;
152    ext->CloseDown = CloseDownProc;
153    ext->MinorOpcode = MinorOpcodeProc;
154    ProcVector[i + EXTENSION_BASE] = MainProc;
155    SwappedProcVector[i + EXTENSION_BASE] = SwappedMainProc;
156    if (NumEvents)
157    {
158        ext->eventBase = lastEvent;
159	ext->eventLast = lastEvent + NumEvents;
160	lastEvent += NumEvents;
161    }
162    else
163    {
164        ext->eventBase = 0;
165        ext->eventLast = 0;
166    }
167    if (NumErrors)
168    {
169        ext->errorBase = lastError;
170	ext->errorLast = lastError + NumErrors;
171	lastError += NumErrors;
172    }
173    else
174    {
175        ext->errorBase = 0;
176        ext->errorLast = 0;
177    }
178
179    return(ext);
180}
181
182_X_EXPORT Bool AddExtensionAlias(char *alias, ExtensionEntry *ext)
183{
184    char *name;
185    char **aliases;
186
187    aliases = (char **)xrealloc(ext->aliases,
188				(ext->num_aliases + 1) * sizeof(char *));
189    if (!aliases)
190	return FALSE;
191    ext->aliases = aliases;
192    name = (char *)xalloc(strlen(alias) + 1);
193    if (!name)
194	return FALSE;
195    strcpy(name,  alias);
196    ext->aliases[ext->num_aliases] = name;
197    ext->num_aliases++;
198    return TRUE;
199}
200
201static int
202FindExtension(char *extname, int len)
203{
204    int i, j;
205
206    for (i=0; i<NumExtensions; i++)
207    {
208	if ((strlen(extensions[i]->name) == len) &&
209	    !strncmp(extname, extensions[i]->name, len))
210	    break;
211	for (j = extensions[i]->num_aliases; --j >= 0;)
212	{
213	    if ((strlen(extensions[i]->aliases[j]) == len) &&
214		!strncmp(extname, extensions[i]->aliases[j], len))
215		break;
216	}
217	if (j >= 0) break;
218    }
219    return ((i == NumExtensions) ? -1 : i);
220}
221
222/*
223 * CheckExtension returns the extensions[] entry for the requested
224 * extension name.  Maybe this could just return a Bool instead?
225 */
226_X_EXPORT ExtensionEntry *
227CheckExtension(const char *extname)
228{
229    int n;
230
231    n = FindExtension((char*)extname, strlen(extname));
232    if (n != -1)
233	return extensions[n];
234    else
235	return NULL;
236}
237
238/*
239 * Added as part of Xace.
240 */
241ExtensionEntry *
242GetExtensionEntry(int major)
243{
244    if (major < EXTENSION_BASE)
245	return NULL;
246    major -= EXTENSION_BASE;
247    if (major >= NumExtensions)
248	return NULL;
249    return extensions[major];
250}
251
252_X_EXPORT void
253DeclareExtensionSecurity(char *extname, Bool secure)
254{
255    int i = FindExtension(extname, strlen(extname));
256    if (i >= 0)
257	XaceHook(XACE_DECLARE_EXT_SECURE, extensions[i], secure);
258}
259
260_X_EXPORT unsigned short
261StandardMinorOpcode(ClientPtr client)
262{
263    return ((xReq *)client->requestBuffer)->data;
264}
265
266_X_EXPORT unsigned short
267MinorOpcodeOfRequest(ClientPtr client)
268{
269    unsigned char major;
270
271    major = ((xReq *)client->requestBuffer)->reqType;
272    if (major < EXTENSION_BASE)
273	return 0;
274    major -= EXTENSION_BASE;
275    if (major >= NumExtensions)
276	return 0;
277    return (*extensions[major]->MinorOpcode)(client);
278}
279
280void
281CloseDownExtensions(void)
282{
283    int i,j;
284
285    for (i = NumExtensions - 1; i >= 0; i--)
286    {
287	(* extensions[i]->CloseDown)(extensions[i]);
288	NumExtensions = i;
289	xfree(extensions[i]->name);
290	for (j = extensions[i]->num_aliases; --j >= 0;)
291	    xfree(extensions[i]->aliases[j]);
292	xfree(extensions[i]->aliases);
293	xfree(extensions[i]);
294    }
295    xfree(extensions);
296    extensions = (ExtensionEntry **)NULL;
297    lastEvent = EXTENSION_EVENT_BASE;
298    lastError = FirstExtensionError;
299}
300
301int
302ProcQueryExtension(ClientPtr client)
303{
304    xQueryExtensionReply reply;
305    int i;
306    REQUEST(xQueryExtensionReq);
307
308    REQUEST_FIXED_SIZE(xQueryExtensionReq, stuff->nbytes);
309
310    reply.type = X_Reply;
311    reply.length = 0;
312    reply.major_opcode = 0;
313    reply.sequenceNumber = client->sequence;
314
315    if ( ! NumExtensions )
316        reply.present = xFalse;
317    else
318    {
319	i = FindExtension((char *)&stuff[1], stuff->nbytes);
320        if (i < 0 || !XaceHook(XACE_EXT_ACCESS, client, extensions[i]))
321            reply.present = xFalse;
322        else
323        {
324            reply.present = xTrue;
325	    reply.major_opcode = extensions[i]->base;
326	    reply.first_event = extensions[i]->eventBase;
327	    reply.first_error = extensions[i]->errorBase;
328	}
329    }
330    WriteReplyToClient(client, sizeof(xQueryExtensionReply), &reply);
331    return(client->noClientException);
332}
333
334int
335ProcListExtensions(ClientPtr client)
336{
337    xListExtensionsReply reply;
338    char *bufptr, *buffer;
339    int total_length = 0;
340
341    REQUEST_SIZE_MATCH(xReq);
342
343    reply.type = X_Reply;
344    reply.nExtensions = 0;
345    reply.length = 0;
346    reply.sequenceNumber = client->sequence;
347    buffer = NULL;
348
349    if ( NumExtensions )
350    {
351        int i, j;
352
353        for (i=0;  i<NumExtensions; i++)
354	{
355	    /* call callbacks to find out whether to show extension */
356	    if (!XaceHook(XACE_EXT_ACCESS, client, extensions[i]))
357		continue;
358
359	    total_length += strlen(extensions[i]->name) + 1;
360	    reply.nExtensions += 1 + extensions[i]->num_aliases;
361	    for (j = extensions[i]->num_aliases; --j >= 0;)
362		total_length += strlen(extensions[i]->aliases[j]) + 1;
363	}
364        reply.length = (total_length + 3) >> 2;
365	buffer = bufptr = (char *)ALLOCATE_LOCAL(total_length);
366	if (!buffer)
367	    return(BadAlloc);
368        for (i=0;  i<NumExtensions; i++)
369        {
370	    int len;
371	    if (!XaceHook(XACE_EXT_ACCESS, client, extensions[i]))
372		continue;
373
374            *bufptr++ = len = strlen(extensions[i]->name);
375	    memmove(bufptr, extensions[i]->name,  len);
376	    bufptr += len;
377	    for (j = extensions[i]->num_aliases; --j >= 0;)
378	    {
379		*bufptr++ = len = strlen(extensions[i]->aliases[j]);
380		memmove(bufptr, extensions[i]->aliases[j],  len);
381		bufptr += len;
382	    }
383	}
384    }
385    WriteReplyToClient(client, sizeof(xListExtensionsReply), &reply);
386    if (reply.length)
387    {
388        WriteToClient(client, total_length, buffer);
389    	DEALLOCATE_LOCAL(buffer);
390    }
391    return(client->noClientException);
392}
393
394#ifdef XSERVER_DTRACE
395void LoadExtensionNames(char **RequestNames) {
396    int i;
397
398    for (i=0; i<NumExtensions; i++) {
399	int r = extensions[i]->base;
400
401	if (RequestNames[r] == NULL) {
402	    RequestNames[r] = strdup(extensions[i]->name);
403	}
404    }
405}
406#endif
407