extension.c revision 35c4bbdf
105b261ecSmrg/***********************************************************
205b261ecSmrg
305b261ecSmrgCopyright 1987, 1998  The Open Group
405b261ecSmrg
505b261ecSmrgPermission to use, copy, modify, distribute, and sell this software and its
605b261ecSmrgdocumentation for any purpose is hereby granted without fee, provided that
705b261ecSmrgthe above copyright notice appear in all copies and that both that
805b261ecSmrgcopyright notice and this permission notice appear in supporting
905b261ecSmrgdocumentation.
1005b261ecSmrg
1105b261ecSmrgThe above copyright notice and this permission notice shall be included in
1205b261ecSmrgall copies or substantial portions of the Software.
1305b261ecSmrg
1405b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1505b261ecSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1605b261ecSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1705b261ecSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1805b261ecSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1905b261ecSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2005b261ecSmrg
2105b261ecSmrgExcept as contained in this notice, the name of The Open Group shall not be
2205b261ecSmrgused in advertising or otherwise to promote the sale, use or other dealings
2305b261ecSmrgin this Software without prior written authorization from The Open Group.
2405b261ecSmrg
2505b261ecSmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
2605b261ecSmrg
2705b261ecSmrg                        All Rights Reserved
2805b261ecSmrg
2935c4bbdfSmrgPermission to use, copy, modify, and distribute this software and its
3035c4bbdfSmrgdocumentation for any purpose and without fee is hereby granted,
3105b261ecSmrgprovided that the above copyright notice appear in all copies and that
3235c4bbdfSmrgboth that copyright notice and this permission notice appear in
3305b261ecSmrgsupporting documentation, and that the name of Digital not be
3405b261ecSmrgused in advertising or publicity pertaining to distribution of the
3535c4bbdfSmrgsoftware without specific, written prior permission.
3605b261ecSmrg
3705b261ecSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
3805b261ecSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
3905b261ecSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
4005b261ecSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
4105b261ecSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
4205b261ecSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
4305b261ecSmrgSOFTWARE.
4405b261ecSmrg
4505b261ecSmrg******************************************************************/
4605b261ecSmrg
4705b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
4805b261ecSmrg#include <dix-config.h>
4905b261ecSmrg#endif
5005b261ecSmrg
5105b261ecSmrg#include <X11/X.h>
5205b261ecSmrg#include <X11/Xproto.h>
5305b261ecSmrg#include "misc.h"
5405b261ecSmrg#include "dixstruct.h"
5505b261ecSmrg#include "extnsionst.h"
5605b261ecSmrg#include "gcstruct.h"
5705b261ecSmrg#include "scrnintstr.h"
5805b261ecSmrg#include "dispatch.h"
594642e01fSmrg#include "privates.h"
604642e01fSmrg#include "registry.h"
6105b261ecSmrg#include "xace.h"
6205b261ecSmrg
6305b261ecSmrg#define LAST_ERROR 255
6405b261ecSmrg
6535c4bbdfSmrgstatic ExtensionEntry **extensions = (ExtensionEntry **) NULL;
6605b261ecSmrg
6705b261ecSmrgint lastEvent = EXTENSION_EVENT_BASE;
6805b261ecSmrgstatic int lastError = FirstExtensionError;
6905b261ecSmrgstatic unsigned int NumExtensions = 0;
7005b261ecSmrg
716747b715SmrgExtensionEntry *
7235c4bbdfSmrgAddExtension(const char *name, int NumEvents, int NumErrors,
7335c4bbdfSmrg             int (*MainProc) (ClientPtr c1),
7435c4bbdfSmrg             int (*SwappedMainProc) (ClientPtr c2),
7535c4bbdfSmrg             void (*CloseDownProc) (ExtensionEntry * e),
7635c4bbdfSmrg             unsigned short (*MinorOpcodeProc) (ClientPtr c3))
7705b261ecSmrg{
7805b261ecSmrg    int i;
7905b261ecSmrg    ExtensionEntry *ext, **newexts;
8005b261ecSmrg
814642e01fSmrg    if (!MainProc || !SwappedMainProc || !MinorOpcodeProc)
8235c4bbdfSmrg        return ((ExtensionEntry *) NULL);
8335c4bbdfSmrg    if ((lastEvent + NumEvents > MAXEVENTS) ||
8435c4bbdfSmrg        (unsigned) (lastError + NumErrors > LAST_ERROR)) {
856747b715Smrg        LogMessage(X_ERROR, "Not enabling extension %s: maximum number of "
866747b715Smrg                   "events or errors exceeded.\n", name);
8735c4bbdfSmrg        return ((ExtensionEntry *) NULL);
886747b715Smrg    }
8905b261ecSmrg
9035c4bbdfSmrg    ext = calloc(sizeof(ExtensionEntry), 1);
9105b261ecSmrg    if (!ext)
9235c4bbdfSmrg        return NULL;
936747b715Smrg    if (!dixAllocatePrivates(&ext->devPrivates, PRIVATE_EXTENSION)) {
9435c4bbdfSmrg        free(ext);
9535c4bbdfSmrg        return NULL;
966747b715Smrg    }
979ace9065Smrg    ext->name = strdup(name);
9805b261ecSmrg    ext->num_aliases = 0;
9935c4bbdfSmrg    ext->aliases = (const char **) NULL;
10035c4bbdfSmrg    if (!ext->name) {
10135c4bbdfSmrg        dixFreePrivates(ext->devPrivates, PRIVATE_EXTENSION);
10235c4bbdfSmrg        free(ext);
10335c4bbdfSmrg        return ((ExtensionEntry *) NULL);
10405b261ecSmrg    }
10505b261ecSmrg    i = NumExtensions;
10635c4bbdfSmrg    newexts = reallocarray(extensions, i + 1, sizeof(ExtensionEntry *));
10735c4bbdfSmrg    if (!newexts) {
10835c4bbdfSmrg        free((void *) ext->name);
10935c4bbdfSmrg        dixFreePrivates(ext->devPrivates, PRIVATE_EXTENSION);
11035c4bbdfSmrg        free(ext);
11135c4bbdfSmrg        return ((ExtensionEntry *) NULL);
11205b261ecSmrg    }
11305b261ecSmrg    NumExtensions++;
11405b261ecSmrg    extensions = newexts;
11505b261ecSmrg    extensions[i] = ext;
11605b261ecSmrg    ext->index = i;
11705b261ecSmrg    ext->base = i + EXTENSION_BASE;
11805b261ecSmrg    ext->CloseDown = CloseDownProc;
11905b261ecSmrg    ext->MinorOpcode = MinorOpcodeProc;
12005b261ecSmrg    ProcVector[i + EXTENSION_BASE] = MainProc;
12105b261ecSmrg    SwappedProcVector[i + EXTENSION_BASE] = SwappedMainProc;
12235c4bbdfSmrg    if (NumEvents) {
12305b261ecSmrg        ext->eventBase = lastEvent;
12435c4bbdfSmrg        ext->eventLast = lastEvent + NumEvents;
12535c4bbdfSmrg        lastEvent += NumEvents;
12605b261ecSmrg    }
12735c4bbdfSmrg    else {
12805b261ecSmrg        ext->eventBase = 0;
12905b261ecSmrg        ext->eventLast = 0;
13005b261ecSmrg    }
13135c4bbdfSmrg    if (NumErrors) {
13205b261ecSmrg        ext->errorBase = lastError;
13335c4bbdfSmrg        ext->errorLast = lastError + NumErrors;
13435c4bbdfSmrg        lastError += NumErrors;
13505b261ecSmrg    }
13635c4bbdfSmrg    else {
13705b261ecSmrg        ext->errorBase = 0;
13805b261ecSmrg        ext->errorLast = 0;
13905b261ecSmrg    }
14005b261ecSmrg
14135c4bbdfSmrg#ifdef X_REGISTRY_REQUEST
1424642e01fSmrg    RegisterExtensionNames(ext);
14335c4bbdfSmrg#endif
1446747b715Smrg    return ext;
14505b261ecSmrg}
14605b261ecSmrg
14735c4bbdfSmrgBool
14835c4bbdfSmrgAddExtensionAlias(const char *alias, ExtensionEntry * ext)
14905b261ecSmrg{
15005b261ecSmrg    char *name;
15135c4bbdfSmrg    const char **aliases;
15205b261ecSmrg
1534642e01fSmrg    if (!ext)
15435c4bbdfSmrg        return FALSE;
15535c4bbdfSmrg    aliases = reallocarray(ext->aliases, ext->num_aliases + 1, sizeof(char *));
15605b261ecSmrg    if (!aliases)
15735c4bbdfSmrg        return FALSE;
15805b261ecSmrg    ext->aliases = aliases;
1599ace9065Smrg    name = strdup(alias);
16005b261ecSmrg    if (!name)
16135c4bbdfSmrg        return FALSE;
16205b261ecSmrg    ext->aliases[ext->num_aliases] = name;
16305b261ecSmrg    ext->num_aliases++;
16405b261ecSmrg    return TRUE;
16505b261ecSmrg}
16605b261ecSmrg
16705b261ecSmrgstatic int
16835c4bbdfSmrgFindExtension(const char *extname, int len)
16905b261ecSmrg{
17005b261ecSmrg    int i, j;
17105b261ecSmrg
17235c4bbdfSmrg    for (i = 0; i < NumExtensions; i++) {
17335c4bbdfSmrg        if ((strlen(extensions[i]->name) == len) &&
17435c4bbdfSmrg            !strncmp(extname, extensions[i]->name, len))
17535c4bbdfSmrg            break;
17635c4bbdfSmrg        for (j = extensions[i]->num_aliases; --j >= 0;) {
17735c4bbdfSmrg            if ((strlen(extensions[i]->aliases[j]) == len) &&
17835c4bbdfSmrg                !strncmp(extname, extensions[i]->aliases[j], len))
17935c4bbdfSmrg                break;
18035c4bbdfSmrg        }
18135c4bbdfSmrg        if (j >= 0)
18235c4bbdfSmrg            break;
18305b261ecSmrg    }
18405b261ecSmrg    return ((i == NumExtensions) ? -1 : i);
18505b261ecSmrg}
18605b261ecSmrg
18705b261ecSmrg/*
18805b261ecSmrg * CheckExtension returns the extensions[] entry for the requested
18905b261ecSmrg * extension name.  Maybe this could just return a Bool instead?
19005b261ecSmrg */
1916747b715SmrgExtensionEntry *
19205b261ecSmrgCheckExtension(const char *extname)
19305b261ecSmrg{
19405b261ecSmrg    int n;
19505b261ecSmrg
19635c4bbdfSmrg    n = FindExtension(extname, strlen(extname));
19705b261ecSmrg    if (n != -1)
19835c4bbdfSmrg        return extensions[n];
19905b261ecSmrg    else
20035c4bbdfSmrg        return NULL;
20105b261ecSmrg}
20205b261ecSmrg
20305b261ecSmrg/*
20405b261ecSmrg * Added as part of Xace.
20505b261ecSmrg */
20605b261ecSmrgExtensionEntry *
20705b261ecSmrgGetExtensionEntry(int major)
20835c4bbdfSmrg{
20905b261ecSmrg    if (major < EXTENSION_BASE)
21035c4bbdfSmrg        return NULL;
21105b261ecSmrg    major -= EXTENSION_BASE;
21205b261ecSmrg    if (major >= NumExtensions)
21335c4bbdfSmrg        return NULL;
21405b261ecSmrg    return extensions[major];
21505b261ecSmrg}
21605b261ecSmrg
2176747b715Smrgunsigned short
21805b261ecSmrgStandardMinorOpcode(ClientPtr client)
21905b261ecSmrg{
22035c4bbdfSmrg    return ((xReq *) client->requestBuffer)->data;
22105b261ecSmrg}
22205b261ecSmrg
22305b261ecSmrgvoid
22405b261ecSmrgCloseDownExtensions(void)
22505b261ecSmrg{
22635c4bbdfSmrg    int i, j;
22735c4bbdfSmrg
22835c4bbdfSmrg    for (i = NumExtensions - 1; i >= 0; i--) {
22935c4bbdfSmrg        if (extensions[i]->CloseDown)
23035c4bbdfSmrg            extensions[i]->CloseDown(extensions[i]);
23135c4bbdfSmrg        NumExtensions = i;
23235c4bbdfSmrg        free((void *) extensions[i]->name);
23335c4bbdfSmrg        for (j = extensions[i]->num_aliases; --j >= 0;)
23435c4bbdfSmrg            free((void *) extensions[i]->aliases[j]);
23535c4bbdfSmrg        free(extensions[i]->aliases);
23635c4bbdfSmrg        dixFreePrivates(extensions[i]->devPrivates, PRIVATE_EXTENSION);
23735c4bbdfSmrg        free(extensions[i]);
23805b261ecSmrg    }
2396747b715Smrg    free(extensions);
24035c4bbdfSmrg    extensions = (ExtensionEntry **) NULL;
24105b261ecSmrg    lastEvent = EXTENSION_EVENT_BASE;
24205b261ecSmrg    lastError = FirstExtensionError;
24305b261ecSmrg}
24405b261ecSmrg
24505b261ecSmrgint
24605b261ecSmrgProcQueryExtension(ClientPtr client)
24705b261ecSmrg{
24805b261ecSmrg    xQueryExtensionReply reply;
24905b261ecSmrg    int i;
25035c4bbdfSmrg
25105b261ecSmrg    REQUEST(xQueryExtensionReq);
25205b261ecSmrg
25305b261ecSmrg    REQUEST_FIXED_SIZE(xQueryExtensionReq, stuff->nbytes);
2546747b715Smrg
25535c4bbdfSmrg    reply = (xQueryExtensionReply) {
25635c4bbdfSmrg        .type = X_Reply,
25735c4bbdfSmrg        .sequenceNumber = client->sequence,
25835c4bbdfSmrg        .length = 0,
25935c4bbdfSmrg        .major_opcode = 0
26035c4bbdfSmrg    };
26105b261ecSmrg
26235c4bbdfSmrg    if (!NumExtensions)
26305b261ecSmrg        reply.present = xFalse;
26435c4bbdfSmrg    else {
26535c4bbdfSmrg        i = FindExtension((char *) &stuff[1], stuff->nbytes);
2664642e01fSmrg        if (i < 0 || XaceHook(XACE_EXT_ACCESS, client, extensions[i]))
26705b261ecSmrg            reply.present = xFalse;
26835c4bbdfSmrg        else {
26905b261ecSmrg            reply.present = xTrue;
27035c4bbdfSmrg            reply.major_opcode = extensions[i]->base;
27135c4bbdfSmrg            reply.first_event = extensions[i]->eventBase;
27235c4bbdfSmrg            reply.first_error = extensions[i]->errorBase;
27335c4bbdfSmrg        }
27405b261ecSmrg    }
27505b261ecSmrg    WriteReplyToClient(client, sizeof(xQueryExtensionReply), &reply);
2766747b715Smrg    return Success;
27705b261ecSmrg}
27805b261ecSmrg
27905b261ecSmrgint
28005b261ecSmrgProcListExtensions(ClientPtr client)
28105b261ecSmrg{
28205b261ecSmrg    xListExtensionsReply reply;
28305b261ecSmrg    char *bufptr, *buffer;
28405b261ecSmrg    int total_length = 0;
28505b261ecSmrg
28605b261ecSmrg    REQUEST_SIZE_MATCH(xReq);
28705b261ecSmrg
28835c4bbdfSmrg    reply = (xListExtensionsReply) {
28935c4bbdfSmrg        .type = X_Reply,
29035c4bbdfSmrg        .nExtensions = 0,
29135c4bbdfSmrg        .sequenceNumber = client->sequence,
29235c4bbdfSmrg        .length = 0
29335c4bbdfSmrg    };
29405b261ecSmrg    buffer = NULL;
29505b261ecSmrg
29635c4bbdfSmrg    if (NumExtensions) {
29705b261ecSmrg        int i, j;
29805b261ecSmrg
29935c4bbdfSmrg        for (i = 0; i < NumExtensions; i++) {
30035c4bbdfSmrg            /* call callbacks to find out whether to show extension */
30135c4bbdfSmrg            if (XaceHook(XACE_EXT_ACCESS, client, extensions[i]) != Success)
30235c4bbdfSmrg                continue;
30335c4bbdfSmrg
30435c4bbdfSmrg            total_length += strlen(extensions[i]->name) + 1;
30535c4bbdfSmrg            reply.nExtensions += 1 + extensions[i]->num_aliases;
30635c4bbdfSmrg            for (j = extensions[i]->num_aliases; --j >= 0;)
30735c4bbdfSmrg                total_length += strlen(extensions[i]->aliases[j]) + 1;
30835c4bbdfSmrg        }
3096747b715Smrg        reply.length = bytes_to_int32(total_length);
31035c4bbdfSmrg        buffer = bufptr = malloc(total_length);
31135c4bbdfSmrg        if (!buffer)
31235c4bbdfSmrg            return BadAlloc;
31335c4bbdfSmrg        for (i = 0; i < NumExtensions; i++) {
31435c4bbdfSmrg            int len;
31535c4bbdfSmrg
31635c4bbdfSmrg            if (XaceHook(XACE_EXT_ACCESS, client, extensions[i]) != Success)
31735c4bbdfSmrg                continue;
31805b261ecSmrg
31905b261ecSmrg            *bufptr++ = len = strlen(extensions[i]->name);
32035c4bbdfSmrg            memmove(bufptr, extensions[i]->name, len);
32135c4bbdfSmrg            bufptr += len;
32235c4bbdfSmrg            for (j = extensions[i]->num_aliases; --j >= 0;) {
32335c4bbdfSmrg                *bufptr++ = len = strlen(extensions[i]->aliases[j]);
32435c4bbdfSmrg                memmove(bufptr, extensions[i]->aliases[j], len);
32535c4bbdfSmrg                bufptr += len;
32635c4bbdfSmrg            }
32735c4bbdfSmrg        }
32805b261ecSmrg    }
32905b261ecSmrg    WriteReplyToClient(client, sizeof(xListExtensionsReply), &reply);
33005b261ecSmrg    if (reply.length)
33105b261ecSmrg        WriteToClient(client, total_length, buffer);
3329ace9065Smrg
3339ace9065Smrg    free(buffer);
3346747b715Smrg    return Success;
33505b261ecSmrg}
336