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