Commit | Line | Data |
---|---|---|
a09e091a JB |
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 * | |
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 | ext->num_aliases = 0; | |
99 | ext->aliases = (char **) NULL; | |
100 | if (!ext->name) { | |
101 | dixFreePrivates(ext->devPrivates, PRIVATE_EXTENSION); | |
102 | free(ext); | |
103 | return ((ExtensionEntry *) NULL); | |
104 | } | |
105 | i = NumExtensions; | |
106 | newexts = (ExtensionEntry **) realloc(extensions, | |
107 | (i + 1) * sizeof(ExtensionEntry *)); | |
108 | if (!newexts) { | |
109 | free(ext->name); | |
110 | dixFreePrivates(ext->devPrivates, PRIVATE_EXTENSION); | |
111 | free(ext); | |
112 | return ((ExtensionEntry *) NULL); | |
113 | } | |
114 | NumExtensions++; | |
115 | extensions = newexts; | |
116 | extensions[i] = ext; | |
117 | ext->index = i; | |
118 | ext->base = i + EXTENSION_BASE; | |
119 | ext->CloseDown = CloseDownProc; | |
120 | ext->MinorOpcode = MinorOpcodeProc; | |
121 | ProcVector[i + EXTENSION_BASE] = MainProc; | |
122 | SwappedProcVector[i + EXTENSION_BASE] = SwappedMainProc; | |
123 | if (NumEvents) { | |
124 | ext->eventBase = lastEvent; | |
125 | ext->eventLast = lastEvent + NumEvents; | |
126 | lastEvent += NumEvents; | |
127 | } | |
128 | else { | |
129 | ext->eventBase = 0; | |
130 | ext->eventLast = 0; | |
131 | } | |
132 | if (NumErrors) { | |
133 | ext->errorBase = lastError; | |
134 | ext->errorLast = lastError + NumErrors; | |
135 | lastError += NumErrors; | |
136 | } | |
137 | else { | |
138 | ext->errorBase = 0; | |
139 | ext->errorLast = 0; | |
140 | } | |
141 | ||
142 | RegisterExtensionNames(ext); | |
143 | return ext; | |
144 | } | |
145 | ||
146 | Bool | |
147 | AddExtensionAlias(const char *alias, ExtensionEntry * ext) | |
148 | { | |
149 | char *name; | |
150 | char **aliases; | |
151 | ||
152 | if (!ext) | |
153 | return FALSE; | |
154 | aliases = (char **) realloc(ext->aliases, | |
155 | (ext->num_aliases + 1) * sizeof(char *)); | |
156 | if (!aliases) | |
157 | return FALSE; | |
158 | ext->aliases = aliases; | |
159 | name = strdup(alias); | |
160 | if (!name) | |
161 | return FALSE; | |
162 | ext->aliases[ext->num_aliases] = name; | |
163 | ext->num_aliases++; | |
164 | return TRUE; | |
165 | } | |
166 | ||
167 | static int | |
168 | FindExtension(const char *extname, int len) | |
169 | { | |
170 | int i, j; | |
171 | ||
172 | for (i = 0; i < NumExtensions; i++) { | |
173 | if ((strlen(extensions[i]->name) == len) && | |
174 | !strncmp(extname, extensions[i]->name, len)) | |
175 | break; | |
176 | for (j = extensions[i]->num_aliases; --j >= 0;) { | |
177 | if ((strlen(extensions[i]->aliases[j]) == len) && | |
178 | !strncmp(extname, extensions[i]->aliases[j], len)) | |
179 | break; | |
180 | } | |
181 | if (j >= 0) | |
182 | break; | |
183 | } | |
184 | return ((i == NumExtensions) ? -1 : i); | |
185 | } | |
186 | ||
187 | /* | |
188 | * CheckExtension returns the extensions[] entry for the requested | |
189 | * extension name. Maybe this could just return a Bool instead? | |
190 | */ | |
191 | ExtensionEntry * | |
192 | CheckExtension(const char *extname) | |
193 | { | |
194 | int n; | |
195 | ||
196 | n = FindExtension(extname, strlen(extname)); | |
197 | if (n != -1) | |
198 | return extensions[n]; | |
199 | else | |
200 | return NULL; | |
201 | } | |
202 | ||
203 | /* | |
204 | * Added as part of Xace. | |
205 | */ | |
206 | ExtensionEntry * | |
207 | GetExtensionEntry(int major) | |
208 | { | |
209 | if (major < EXTENSION_BASE) | |
210 | return NULL; | |
211 | major -= EXTENSION_BASE; | |
212 | if (major >= NumExtensions) | |
213 | return NULL; | |
214 | return extensions[major]; | |
215 | } | |
216 | ||
217 | unsigned short | |
218 | StandardMinorOpcode(ClientPtr client) | |
219 | { | |
220 | return ((xReq *) client->requestBuffer)->data; | |
221 | } | |
222 | ||
223 | void | |
224 | CloseDownExtensions(void) | |
225 | { | |
226 | int i, j; | |
227 | ||
228 | for (i = NumExtensions - 1; i >= 0; i--) { | |
229 | if (extensions[i]->CloseDown) | |
230 | extensions[i]->CloseDown(extensions[i]); | |
231 | NumExtensions = i; | |
232 | free(extensions[i]->name); | |
233 | for (j = extensions[i]->num_aliases; --j >= 0;) | |
234 | free(extensions[i]->aliases[j]); | |
235 | free(extensions[i]->aliases); | |
236 | dixFreePrivates(extensions[i]->devPrivates, PRIVATE_EXTENSION); | |
237 | free(extensions[i]); | |
238 | } | |
239 | free(extensions); | |
240 | extensions = (ExtensionEntry **) NULL; | |
241 | lastEvent = EXTENSION_EVENT_BASE; | |
242 | lastError = FirstExtensionError; | |
243 | } | |
244 | ||
245 | int | |
246 | ProcQueryExtension(ClientPtr client) | |
247 | { | |
248 | xQueryExtensionReply reply; | |
249 | int i; | |
250 | ||
251 | REQUEST(xQueryExtensionReq); | |
252 | ||
253 | REQUEST_FIXED_SIZE(xQueryExtensionReq, stuff->nbytes); | |
254 | ||
255 | reply = (xQueryExtensionReply) { | |
256 | .type = X_Reply, | |
257 | .sequenceNumber = client->sequence, | |
258 | .length = 0, | |
259 | .major_opcode = 0 | |
260 | }; | |
261 | ||
262 | if (!NumExtensions) | |
263 | reply.present = xFalse; | |
264 | else { | |
265 | i = FindExtension((char *) &stuff[1], stuff->nbytes); | |
266 | if (i < 0 || XaceHook(XACE_EXT_ACCESS, client, extensions[i])) | |
267 | reply.present = xFalse; | |
268 | else { | |
269 | reply.present = xTrue; | |
270 | reply.major_opcode = extensions[i]->base; | |
271 | reply.first_event = extensions[i]->eventBase; | |
272 | reply.first_error = extensions[i]->errorBase; | |
273 | } | |
274 | } | |
275 | WriteReplyToClient(client, sizeof(xQueryExtensionReply), &reply); | |
276 | return Success; | |
277 | } | |
278 | ||
279 | int | |
280 | ProcListExtensions(ClientPtr client) | |
281 | { | |
282 | xListExtensionsReply reply; | |
283 | char *bufptr, *buffer; | |
284 | int total_length = 0; | |
285 | ||
286 | REQUEST_SIZE_MATCH(xReq); | |
287 | ||
288 | reply = (xListExtensionsReply) { | |
289 | .type = X_Reply, | |
290 | .nExtensions = 0, | |
291 | .sequenceNumber = client->sequence, | |
292 | .length = 0 | |
293 | }; | |
294 | buffer = NULL; | |
295 | ||
296 | if (NumExtensions) { | |
297 | int i, j; | |
298 | ||
299 | for (i = 0; i < NumExtensions; i++) { | |
300 | /* call callbacks to find out whether to show extension */ | |
301 | if (XaceHook(XACE_EXT_ACCESS, client, extensions[i]) != Success) | |
302 | continue; | |
303 | ||
304 | total_length += strlen(extensions[i]->name) + 1; | |
305 | reply.nExtensions += 1 + extensions[i]->num_aliases; | |
306 | for (j = extensions[i]->num_aliases; --j >= 0;) | |
307 | total_length += strlen(extensions[i]->aliases[j]) + 1; | |
308 | } | |
309 | reply.length = bytes_to_int32(total_length); | |
310 | buffer = bufptr = malloc(total_length); | |
311 | if (!buffer) | |
312 | return BadAlloc; | |
313 | for (i = 0; i < NumExtensions; i++) { | |
314 | int len; | |
315 | ||
316 | if (XaceHook(XACE_EXT_ACCESS, client, extensions[i]) != Success) | |
317 | continue; | |
318 | ||
319 | *bufptr++ = len = strlen(extensions[i]->name); | |
320 | memmove(bufptr, extensions[i]->name, len); | |
321 | bufptr += len; | |
322 | for (j = extensions[i]->num_aliases; --j >= 0;) { | |
323 | *bufptr++ = len = strlen(extensions[i]->aliases[j]); | |
324 | memmove(bufptr, extensions[i]->aliases[j], len); | |
325 | bufptr += len; | |
326 | } | |
327 | } | |
328 | } | |
329 | WriteReplyToClient(client, sizeof(xListExtensionsReply), &reply); | |
330 | if (reply.length) | |
331 | WriteToClient(client, total_length, buffer); | |
332 | ||
333 | free(buffer); | |
334 | return Success; | |
335 | } |