dispatch.c revision 34f90d55
1/*
2 * protocol dispatcher
3 */
4/*
5
6Copyright 1990, 1991, 1998  The Open Group
7
8Permission to use, copy, modify, distribute, and sell this software and its
9documentation for any purpose is hereby granted without fee, provided that
10the above copyright notice appear in all copies and that both that
11copyright notice and this permission notice appear in supporting
12documentation.
13
14The above copyright notice and this permission notice shall be included in
15all copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
20OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24Except as contained in this notice, the name of The Open Group shall not be
25used in advertising or otherwise to promote the sale, use or other dealings
26in this Software without prior written authorization from The Open Group.
27
28 * Copyright 1990, 1991 Network Computing Devices;
29 * Portions Copyright 1987 by Digital Equipment Corporation
30 *
31 * Permission to use, copy, modify, distribute, and sell this software and
32 * its documentation for any purpose is hereby granted without fee, provided
33 * that the above copyright notice appear in all copies and that both that
34 * copyright notice and this permission notice appear in supporting
35 * documentation, and that the names of Network Computing Devices, or Digital
36 * not be used in advertising or publicity pertaining to distribution
37 * of the software without specific, written prior permission.
38 *
39 * NETWORK COMPUTING DEVICES, AND DIGITAL DISCLAIM ALL WARRANTIES WITH
40 * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
41 * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES,
42 * OR DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
43 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
44 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
45 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
46 * THIS SOFTWARE.
47 */
48
49#include	"config.h"
50
51#include	<stdlib.h>
52#include	"dispatch.h"
53#include	"swapreq.h"
54#include	"swaprep.h"
55
56#include	<X11/fonts/FS.h>
57#include	<X11/fonts/FSproto.h>
58#include	"clientstr.h"
59#include	"authstr.h"
60#include	"osstruct.h"
61#include	"extentst.h"
62#include	"globals.h"
63#include	"fsresource.h"
64#include	"difsfnst.h"
65#include	<X11/fonts/fontstruct.h>
66#include	"site.h"
67#include	"fsevents.h"
68#include	"globals.h"
69#include	"difs.h"
70#include	"access.h"
71
72static void kill_all_clients(void);
73
74volatile char        dispatchException = 0;
75volatile char        isItTimeToYield;
76
77ClientPtr   currentClient;
78
79static int  nClients = 0;
80static int  nextFreeClientID;
81
82#define	MAJOROP	((fsReq *)client->requestBuffer)->reqType
83
84#define	ALL_FORMAT_BITS	(BitmapFormatByteOrderMask | \
85			 BitmapFormatBitOrderMask | \
86			 BitmapFormatScanlineUnitMask | \
87			 BitmapFormatScanlinePadMask | \
88			 BitmapFormatImageRectMask)
89
90#define	ALL_FORMAT_MASK_BITS	(BitmapFormatMaskByte | \
91				 BitmapFormatMaskBit | \
92				 BitmapFormatMaskImageRectangle | \
93				 BitmapFormatMaskScanLinePad | \
94				 BitmapFormatMaskScanLineUnit)
95
96void
97Dispatch(void)
98{
99    int         nready,
100                result;
101    int        *clientReady;
102    ClientPtr   client;
103    int		op;
104
105    nextFreeClientID = MINCLIENT;
106    nClients = 0;
107
108    clientReady = (int *) ALLOCATE_LOCAL(sizeof(int) * MaxClients);
109    if (!clientReady)
110	return;
111
112    while (1) {
113	/* wait for something */
114	nready = WaitForSomething(clientReady);
115
116	while (!dispatchException && (--nready >= 0)) {
117	    client = currentClient = clients[clientReady[nready]];
118
119	    /* Client can be NULL if CloseDownClient() is called during
120	       this dispatchException loop. */
121	    if (client == (ClientPtr)NULL) continue;
122
123	    isItTimeToYield = FALSE;
124
125	    while (!isItTimeToYield) {
126		result = ReadRequest(client);
127		if (result <= 0) {
128		    if (result < 0)
129			CloseDownClient(client);
130		    break;
131		}
132		client->sequence++;
133
134		if (result > (MAX_REQUEST_SIZE << 2))
135		    result = FSBadLength;
136		else
137		{
138		    op = MAJOROP;
139		    if (op >= NUM_PROC_VECTORS)
140			result = ProcBadRequest (client);
141		    else if (*client->requestVector[op] != NULL)
142			result = (*client->requestVector[op]) (client);
143		    else
144			result = FSBadRequest;
145		}
146		if (result != FSSuccess) {
147		    if (client->noClientException != FSSuccess)
148			CloseDownClient(client);
149		    break;
150		}
151	    }
152	    FlushAllOutput ();
153	}
154	/* reset if server is a drone and has run out of clients */
155	if (drone_server && nClients == 0) {
156	    dispatchException |= DE_RESET;
157	}
158	if (dispatchException) {
159	    /* re-read the config file */
160	    if (dispatchException & DE_RECONFIG) {
161		NoticeF("re-reading config file\n");
162		if (ReadConfigFile(configfilename) != FSSuccess)
163		    ErrorF("couldn't parse config file\n");
164		SetConfigValues();
165		dispatchException &= ~DE_RECONFIG;
166	    }
167	    /* flush all the caches */
168	    if (dispatchException & DE_FLUSH) {
169		NoticeF("flushing all caches\n");
170		dispatchException &= ~DE_FLUSH;
171	    }
172	    /* reset */
173	    if (dispatchException & DE_RESET) {
174		NoticeF("resetting\n");
175		break;
176	    }
177	    /* die *now* */
178	    if (dispatchException & DE_TERMINATE) {
179		NoticeF("terminating\n");
180		kill_all_clients();
181		CloseSockets();
182		CloseErrors();
183		exit(0);
184		break;
185	    }
186	}
187    }
188    kill_all_clients();
189    dispatchException = 0;
190}
191
192int
193ProcInitialConnection(ClientPtr client)
194{
195    REQUEST(fsFakeReq);
196    fsConnClientPrefix *prefix;
197    int         whichbyte = 1;
198
199    prefix = (fsConnClientPrefix *) stuff+1;
200    if ((prefix->byteOrder != 'l') && (prefix->byteOrder != 'B'))
201	return (client->noClientException = -2);
202    if (((*(char *) &whichbyte) && (prefix->byteOrder == 'B')) ||
203	    (!(*(char *) &whichbyte) && (prefix->byteOrder == 'l'))) {
204	int status;
205
206	client->swapped = TRUE;
207	status = SwapConnClientPrefix(client, prefix);
208	if (status != FSSuccess)
209	    return (status);
210    }
211    client->major_version = prefix->major_version;
212    client->minor_version = prefix->minor_version;
213    stuff->reqType = 2;
214    stuff->length += prefix->auth_len;
215    if (client->swapped) {
216	stuff->length = lswaps(stuff->length);
217    }
218    ResetCurrentRequest(client);
219    return client->noClientException;
220}
221
222int
223ProcEstablishConnection(ClientPtr client)
224{
225    fsConnClientPrefix *prefix;
226    int         ret;
227    pointer     auth_data;
228    char       *ad;
229    char       *server_auth_data;
230    AuthPtr     client_auth;
231    int         i,
232                num_alts,
233                altlen,
234                auth_accept,
235                auth_index,
236                auth_len;
237    AlternateServerPtr altservers;
238
239    REQUEST(fsFakeReq);
240
241    prefix = (fsConnClientPrefix *) stuff+1;
242    auth_data = prefix + sz_fsConnClientPrefix;
243    client_auth = (AuthPtr) ALLOCATE_LOCAL(prefix->num_auths * sizeof(AuthRec));
244    if (!client_auth) {
245	SendErrToClient(client, FSBadAlloc, (pointer) 0);
246	return FSBadAlloc;
247    }
248/* XXXX -- this needs work for multiple auth replies */
249
250    /* build up a list of the stuff */
251    for (i = 0, ad = auth_data; i < (int)prefix->num_auths; i++) {
252	if (ad - (char *)auth_data > (stuff->length << 2) - 4) {
253	    int lengthword = stuff->length;
254
255	    SendErrToClient(client, FSBadLength, (pointer)&lengthword);
256	    return (FSBadLength);
257	}
258	/* copy carefully in case wire data is not aligned */
259	client_auth[i].namelen = (((unsigned char *)ad)[0] << 8) +
260				 ((unsigned char *)ad)[1];
261	ad += 2;
262	client_auth[i].datalen = (((unsigned char *)ad)[0] << 8) +
263				 ((unsigned char *)ad)[1];
264	ad += 2;
265	client_auth[i].name = (char *) ad;
266	ad += client_auth[i].namelen;
267	client_auth[i].data = (char *) ad;
268	ad += client_auth[i].datalen;
269    }
270    if (!(int)prefix->num_auths)
271	ad += 4;
272    if (ad - (char *)auth_data > (stuff->length << 2)) {
273	int lengthword = stuff->length;
274
275	SendErrToClient(client, FSBadLength, (pointer)&lengthword);
276	return (FSBadLength);
277    }
278
279    num_alts = ListAlternateServers(&altservers);
280    for (i = 0, altlen = 0; i < num_alts; i++) {
281	/* subset + len + namelen + pad */
282	altlen += (2 + altservers[i].namelen + 3) >> 2;
283    }
284
285    auth_index = prefix->num_auths;
286    client->auth_generation = 0;
287    ret = CheckClientAuthorization(client, client_auth,
288		    &auth_accept, &auth_index, &auth_len, &server_auth_data);
289    if (auth_index > 0)
290    {
291	AuthContextPtr authp;
292	authp = (AuthContextPtr) fsalloc(sizeof(AuthContextRec));
293	if (!authp) {
294	    SendErrToClient(client, FSBadAlloc, (pointer) 0);
295	    return FSBadAlloc;
296	}
297	authp->authname =
298	    (char *) fsalloc(client_auth[auth_index - 1].namelen + 1);
299	authp->authdata =
300	    (char *) fsalloc(client_auth[auth_index - 1].datalen + 1);
301	if (!authp->authname || !authp->authdata) {
302	    fsfree((char *) authp->authname);
303	    fsfree((char *) authp->authdata);
304	    fsfree((char *) authp);
305	    SendErrToClient(client, FSBadAlloc, (pointer) 0);
306	    return FSBadAlloc;
307	}
308	memmove( authp->authname, client_auth[auth_index - 1].name,
309	      client_auth[auth_index - 1].namelen);
310	memmove( authp->authdata, client_auth[auth_index - 1].data,
311	      client_auth[auth_index - 1].datalen);
312	/* Save it with a zero resource id...  subsequent
313	   SetAuthorizations of None will find it.  And it will be freed
314	   by FreeClientResources when the connection closes.  */
315	if (!AddResource(client->index, 0, RT_AUTHCONT,(pointer) authp))
316	{
317	    fsfree((char *) authp->authname);
318	    fsfree((char *) authp->authdata);
319	    fsfree((char *) authp);
320	    SendErrToClient(client, FSBadAlloc, (pointer) 0);
321	    return FSBadAlloc;
322	}
323	client->auth = client->default_auth = authp;
324    }
325    else
326	client->auth = client->default_auth = (AuthContextPtr)0;
327
328    DEALLOCATE_LOCAL(client_auth);
329
330    if (ret != FSSuccess) {
331	SendErrToClient(client, FSBadAlloc, (pointer) 0);
332	return FSBadAlloc;
333    }
334    else {
335	fsConnSetup csp = {
336	    .status = auth_accept,
337	    /* we implement backwards compatibility for version 1.0 */
338	    .major_version = (client->major_version == 1) ?
339	        client->major_version : FS_PROTOCOL,
340	    .minor_version = FS_PROTOCOL_MINOR,
341	    .num_alternates = num_alts,
342	    .alternate_len = altlen,
343	    .auth_len = auth_len >> 2,
344	    .auth_index = auth_index
345	};
346	if (client->swapped) {
347	    WriteSConnSetup(client, &csp);
348	} else {
349	    (void) WriteToClient(client, SIZEOF(fsConnSetup), (char *) &csp);
350	}
351    }
352
353    /* send the alternates info */
354    for (i = 0; i < num_alts; i++) {
355	char        tmp[258];
356
357	/* WriteToClient pads, so we have to fake some things */
358	tmp[0] = altservers[i].subset;
359	tmp[1] = altservers[i].namelen;
360	memmove( (char *) &tmp[2], altservers[i].name, altservers[i].namelen);
361	(void) WriteToClient(client, altservers[i].namelen + 2, tmp);
362    }
363
364    if (auth_len)
365	(void) WriteToClient(client, auth_len, (char *) server_auth_data);
366
367    if (auth_accept != AuthSuccess) {
368	nClients--;
369	return (client->noClientException = -2);
370    }
371    client->requestVector = client->swapped ? SwappedProcVector : ProcVector;
372    client->sequence = 0;
373    if (client->swapped)
374	(void) WriteSConnectionInfo(client, ConnInfoLen, ConnectionInfo);
375    else
376	(void) WriteToClient(client, ConnInfoLen, ConnectionInfo);
377
378#ifdef DEBUG
379    fprintf(stderr, "Establishing new connection\n");
380#endif
381
382    return client->noClientException;
383}
384
385/*
386 * NOTE -- the incoming data may be mangled
387 */
388
389void
390DoSendErrToClient(
391    ClientPtr   client,
392    int         error,
393    pointer     data)		/* resource id, format, resolution, etc */
394{
395    fsError     rep = {
396	.type = FS_Error,
397	.request = error,
398	.sequenceNumber = client->sequence,
399	.timestamp = GetTimeInMillis(),
400	.major_opcode = ((fsReq *) client->requestBuffer)->reqType,
401	.minor_opcode = MinorOpcodeOfRequest(client)
402    };
403    int         extralen = 0;
404
405    switch (error) {
406    case FSBadFormat:
407	extralen = SIZEOF(fsBitmapFormat);
408	break;
409    case FSBadFont:
410    case FSBadAccessContext:
411    case FSBadIDChoice:
412    case FSBadEventMask:
413	if (data) {
414	    if (client->swapped)
415	        SwapLongs((long *) data, 1);
416	    extralen = 4;
417	}
418	break;
419    case FSBadRange:
420	extralen = SIZEOF(fsRange);
421	break;
422    case FSBadResolution:
423	if (data) {
424	    if (client->swapped)
425	        SwapShorts((short *) data, 1);
426	    /* note sneaky hack */
427	    rep.pad = *(CARD16 *) data;
428	    data = (char *)data + 2;
429	    extralen = 4;
430	}
431	break;
432    case FSBadLength:
433	if (data) {
434	    if (client->swapped)
435	        SwapLongs((long *) data, 1);
436	    extralen = 4;
437	}
438	break;
439    default:
440	/* nothing else to send */
441	break;
442    }
443
444    rep.length = (SIZEOF(fsError) + extralen) >> 2;
445
446    WriteErrorToClient(client, &rep);
447
448    if (extralen)
449	WriteToClient(client, extralen, (char *) data);
450}
451
452/* ARGSUSED */
453int
454ProcBadRequest(ClientPtr client)
455{
456    SendErrToClient(client, FSBadRequest, NULL);
457    return FSBadRequest;
458}
459
460int
461ProcNoop(ClientPtr client)
462{
463    REQUEST(fsReq);
464    REQUEST_AT_LEAST_SIZE(fsReq);
465
466    return client->noClientException;
467}
468
469int
470ProcListCatalogues(ClientPtr client)
471{
472    int         len,
473                num;
474    char       *catalogues;
475    fsListCataloguesReply rep = {
476	.type = FS_Reply,
477	.sequenceNumber = client->sequence,
478	.num_replies = 0
479    };
480
481    REQUEST(fsListCataloguesReq);
482    REQUEST_AT_LEAST_SIZE(fsListCataloguesReq);
483
484    num = ListCatalogues((char *)stuff + SIZEOF(fsListCataloguesReq),
485			 stuff->nbytes, stuff->maxNames,
486			 &catalogues, &len);
487    rep.num_catalogues = num;
488    rep.length = (SIZEOF(fsListCataloguesReply) + len + 3) >> 2;
489
490    WriteReplyToClient(client, SIZEOF(fsListCataloguesReply), &rep);
491    (void) WriteToClient(client, len, (char *) catalogues);
492    fsfree((char *) catalogues);
493    return client->noClientException;
494}
495
496int
497ProcSetCatalogues(ClientPtr client)
498{
499    char       *new_cat;
500    int         err,
501                len;
502    int         num;
503
504    REQUEST(fsSetCataloguesReq);
505    REQUEST_AT_LEAST_SIZE(fsSetCataloguesReq);
506
507    if (stuff->num_catalogues == 0) {
508	/* use the default */
509	num = ListCatalogues("*", 1, 10000, &new_cat, &len);
510    } else {
511	num = stuff->num_catalogues;
512	err = ValidateCatalogues(&num, (char *)stuff + SIZEOF(fsSetCataloguesReq));
513	if (err == FSSuccess) {
514	    len = (stuff->length << 2) - SIZEOF(fsSetCataloguesReq);
515	    new_cat = (char *) fsalloc(len);
516	    if (!new_cat)
517		return FSBadAlloc;
518	    memmove( new_cat, (char *)stuff + SIZEOF(fsSetCataloguesReq), len);
519	} else {
520	    SendErrToClient(client, err, (pointer) &num);
521	    return err;
522	}
523    }
524    if (client->catalogues)
525	fsfree((char *) client->catalogues);
526    client->catalogues = new_cat;
527    client->num_catalogues = num;
528    return client->noClientException;
529}
530
531int
532ProcGetCatalogues(ClientPtr client)
533{
534    int         len,
535                i,
536                size;
537    char       *cp;
538
539    REQUEST(fsGetCataloguesReq);
540    REQUEST_AT_LEAST_SIZE(fsGetCataloguesReq);
541
542    for (i = 0, len = 0, cp = client->catalogues;
543	    i < client->num_catalogues; i++) {
544	size = *cp++;
545	len += size + 1;	/* str length + size byte */
546	cp += size;
547    }
548
549    {
550        fsGetCataloguesReply rep = {
551	    .type = FS_Reply,
552	    .num_catalogues = client->num_catalogues,
553	    .sequenceNumber = client->sequence,
554	    .length = (SIZEOF(fsGetCataloguesReply) + len + 3) >> 2
555	};
556
557	WriteReplyToClient(client, SIZEOF(fsGetCataloguesReply), &rep);
558    }
559    (void) WriteToClient(client, len, client->catalogues);
560
561    return client->noClientException;
562}
563
564int
565ProcCreateAC(ClientPtr client)
566{
567    AuthPtr     acp;
568    AuthContextPtr authp;
569    int         accept,
570                i,
571                err,
572                index,
573                size;
574    char       *ad;
575    char       *auth_data;
576
577    REQUEST(fsCreateACReq);
578    REQUEST_AT_LEAST_SIZE(fsCreateACReq);
579
580    authp = (AuthContextPtr) LookupIDByType(client->index, stuff->acid,
581					    RT_AUTHCONT);
582    if (authp) {
583	int aligned_acid = stuff->acid;
584	SendErrToClient(client, FSBadIDChoice, (pointer) &aligned_acid);
585	return FSBadIDChoice;
586    }
587    acp = NULL;
588    if (stuff->num_auths)
589    {
590    	acp = (AuthPtr) ALLOCATE_LOCAL(stuff->num_auths * sizeof(AuthRec));
591    	if (!acp) {
592	    SendErrToClient(client, FSBadAlloc, (pointer) NULL);
593	    return FSBadAlloc;
594    	}
595    }
596    /* build up a list of the stuff */
597    for (i = 0, ad = (char *)stuff + SIZEOF(fsCreateACReq);
598         i < (int)stuff->num_auths; i++) {
599	if (ad - (char *)stuff + SIZEOF(fsCreateACReq) >
600	    (stuff->length << 2) - 4) {
601	    int lengthword = stuff->length;
602
603	    SendErrToClient(client, FSBadLength, (pointer)&lengthword);
604	    return (FSBadLength);
605	}
606	/* copy carefully in case data is not aligned */
607	acp[i].namelen = (((unsigned char *)ad)[0] << 8) +
608			 ((unsigned char *)ad)[1];
609	ad += 2;
610	acp[i].datalen = (((unsigned char *)ad)[0] << 8) +
611			 ((unsigned char *)ad)[1];
612	ad += 2;
613	acp[i].name = (char *) ad;
614	ad += acp[i].namelen;
615	acp[i].data = (char *) ad;
616	ad += acp[i].datalen;
617    }
618    if (ad - (char *)stuff > (stuff->length << 2)) {
619	int lengthword = stuff->length;
620
621	SendErrToClient(client, FSBadLength, (pointer)&lengthword);
622	return (FSBadLength);
623    }
624
625/* XXX needs work for AuthContinue */
626    index = stuff->num_auths;
627    err = CheckClientAuthorization(client, acp, &accept, &index, &size,
628				   &auth_data);
629
630    if (err != FSSuccess) {
631	SendErrToClient(client, err, (pointer) 0);
632	if (acp)
633	    DEALLOCATE_LOCAL(acp);
634	return err;
635    }
636    authp = (AuthContextPtr) fsalloc(sizeof(AuthContextRec));
637    if (!authp) {
638	goto alloc_failure;
639    }
640    authp->authname = NULL;
641    authp->authdata = NULL;
642    if (index > 0)
643    {
644	authp->authname = (char *) fsalloc(acp[index - 1].namelen + 1);
645	authp->authdata = (char *) fsalloc(acp[index - 1].datalen + 1);
646	if (!authp->authname || !authp->authdata) {
647	    fsfree((char *) authp->authname);
648	    fsfree((char *) authp->authdata);
649	    fsfree((char *) authp);
650	    goto alloc_failure;
651	}
652	memmove( authp->authname, acp[index - 1].name, acp[index - 1].namelen);
653	memmove( authp->authdata, acp[index - 1].data, acp[index - 1].datalen);
654    }
655    else
656	size = 0;
657    authp->acid = stuff->acid;
658    if (!AddResource(client->index, stuff->acid, RT_AUTHCONT,(pointer) authp))
659    {
660alloc_failure:
661	SendErrToClient(client, FSBadAlloc, (pointer) 0);
662	if (acp)
663	    DEALLOCATE_LOCAL(acp);
664	return FSBadAlloc;
665    }
666    DEALLOCATE_LOCAL(acp);
667    {
668        fsCreateACReply rep = {
669	    .type = FS_Reply,
670	    .auth_index = index,
671	    .sequenceNumber = client->sequence,
672	    .status = accept,
673	    .length = (SIZEOF(fsCreateACReply) + size) >> 2
674	};
675
676	WriteReplyToClient(client, SIZEOF(fsCreateACReply), &rep);
677    }
678    if (size)
679	(void) WriteToClient(client, size, auth_data);
680
681    return client->noClientException;
682}
683
684/* ARGSUSED */
685int
686DeleteAuthCont (pointer value, FSID id)
687{
688    AuthContextPtr  authp = (AuthContextPtr) value;
689
690    if (authp->authname)
691	fsfree (authp->authname);
692    if (authp->authdata)
693	fsfree (authp->authdata);
694    fsfree (authp);
695    return 1;
696}
697
698int
699ProcFreeAC(ClientPtr client)
700{
701    AuthContextPtr authp;
702
703    REQUEST(fsFreeACReq);
704    REQUEST_AT_LEAST_SIZE(fsFreeACReq);
705    authp = (AuthContextPtr) LookupIDByType(client->index, stuff->id,
706					  RT_AUTHCONT);
707    if (!authp) {
708	int aligned_id = stuff->id;
709	SendErrToClient(client, FSBadIDChoice, (pointer) &aligned_id);
710	return FSBadIDChoice;
711    }
712    if (client->auth == authp)
713	client->auth = client->default_auth;
714    FreeResource(client->index, stuff->id, RT_NONE);
715    return client->noClientException;
716}
717
718int
719ProcSetAuthorization(ClientPtr client)
720{
721    AuthContextPtr acp;
722
723    REQUEST(fsSetAuthorizationReq);
724    REQUEST_AT_LEAST_SIZE(fsSetAuthorizationReq);
725    acp = (AuthContextPtr) LookupIDByType(client->index, stuff->id,
726					  RT_AUTHCONT);
727    if (!acp) {
728	int aligned_id = stuff->id;
729	SendErrToClient(client, FSBadIDChoice, (pointer) &aligned_id);
730	return FSBadIDChoice;
731    }
732    client->auth = acp;		/* XXX does this need a refcount? */
733    return client->noClientException;
734}
735
736int
737ProcSetResolution(ClientPtr client)
738{
739    fsResolution *new_res;
740
741    REQUEST(fsSetResolutionReq);
742    REQUEST_AT_LEAST_SIZE(fsSetResolutionReq);
743
744    if ((stuff->length << 2) - SIZEOF(fsSetResolutionReq) <
745        stuff->num_resolutions * SIZEOF(fsResolution)) {
746	int lengthword = stuff->length;
747
748	SendErrToClient(client, FSBadLength, &lengthword);
749	return FSBadLength;
750    }
751    new_res = (fsResolution *)
752	fsalloc(SIZEOF(fsResolution) * stuff->num_resolutions);
753    if (!new_res) {
754	SendErrToClient(client, FSBadAlloc, NULL);
755	return FSBadAlloc;
756    }
757    fsfree((char *) client->resolutions);
758    memmove( (char *) new_res, (char *)stuff + SIZEOF(fsSetResolutionReq),
759	  (stuff->num_resolutions * SIZEOF(fsResolution)));
760    client->resolutions = new_res;
761    client->num_resolutions = stuff->num_resolutions;
762
763    return client->noClientException;
764}
765
766int
767ProcGetResolution(ClientPtr client)
768{
769    REQUEST(fsReq);
770    REQUEST_AT_LEAST_SIZE(fsReq);
771
772    if ((stuff->length << 2) - SIZEOF(fsResolution) < client->num_resolutions *
773	sizeof(fsResolution)) {
774	int lengthword = stuff->length;
775
776	SendErrToClient(client, FSBadLength, &lengthword);
777	return FSBadLength;
778    }
779    else {
780	fsGetResolutionReply reply = {
781	    .type = FS_Reply,
782	    .num_resolutions = client->num_resolutions,
783	    .sequenceNumber = client->sequence,
784	    .length = (SIZEOF(fsGetResolutionReply) +
785		       client->num_resolutions * SIZEOF(fsResolution)) >> 2
786	};
787
788	WriteReplyToClient(client, SIZEOF(fsGetResolutionReply), &reply);
789    }
790    if (client->swapped)
791	client->pSwapReplyFunc = CopySwap16Write;
792
793    WriteSwappedDataToClient(client,
794       (client->num_resolutions * SIZEOF(fsResolution)), (short *)client->resolutions);
795
796    return client->noClientException;
797}
798
799int
800ProcListFonts(ClientPtr client)
801{
802    REQUEST(fsListFontsReq);
803    REQUEST_FIXED_SIZE(fsListFontsReq, stuff->nbytes);
804
805    return ListFonts(client, stuff->nbytes,
806		     (unsigned char *)stuff + SIZEOF(fsListFontsReq),
807		     stuff->maxNames);
808}
809
810int
811ProcListFontsWithXInfo(ClientPtr client)
812{
813    REQUEST(fsListFontsWithXInfoReq);
814    REQUEST_FIXED_SIZE(fsListFontsWithXInfoReq, stuff->nbytes);
815
816    return StartListFontsWithInfo(client, stuff->nbytes,
817				  (unsigned char *)stuff + SIZEOF(fsListFontsWithXInfoReq), stuff->maxNames);
818}
819
820int
821ProcOpenBitmapFont(ClientPtr client)
822{
823    FontPtr     pfont;
824    int         nbytes,
825                err;
826    unsigned char *fname;
827
828    REQUEST(fsOpenBitmapFontReq);
829    fname = (unsigned char *)stuff + SIZEOF(fsOpenBitmapFontReq);
830    nbytes = *fname++;
831
832    REQUEST_FIXED_SIZE(fsOpenBitmapFontReq, (nbytes + 1));
833
834    pfont = (FontPtr) LookupIDByType(client->index, stuff->fid, RT_FONT);
835    if (pfont) {
836	int aligned_fid = stuff->fid;
837	SendErrToClient(client, FSBadIDChoice, (pointer) &aligned_fid);
838	return FSBadIDChoice;
839    }
840    if (stuff->format_hint != 0 &&
841	    stuff->format_hint & ~ALL_FORMAT_BITS) {
842	int aligned_format_hint = stuff->format_hint;
843	SendErrToClient(client, FSBadFormat, (pointer) &aligned_format_hint);
844	return FSBadFormat;
845    }
846    if (stuff->format_mask & ~ALL_FORMAT_MASK_BITS) {
847	int aligned_format_mask = stuff->format_mask;
848	SendErrToClient(client, FSBadFormat, (pointer) &aligned_format_mask);
849	return FSBadFormat;
850    }
851    err = OpenFont(client, stuff->fid, stuff->format_hint, stuff->format_mask,
852		   nbytes, (char *) fname);
853
854    if (err == FSSuccess) {
855	return client->noClientException;
856    } else {
857	return err;
858    }
859}
860
861int
862ProcQueryXInfo(ClientPtr client)
863{
864    ClientFontPtr cfp;
865    int         err,
866                lendata;
867    fsQueryXInfoReply reply = {
868	.type = FS_Reply,
869	.sequenceNumber = client->sequence
870    };
871    fsPropInfo *prop_info;
872
873    REQUEST(fsQueryXInfoReq);
874
875    REQUEST_AT_LEAST_SIZE(fsQueryXInfoReq);
876
877    cfp = (ClientFontPtr) LookupIDByType(client->index, stuff->id, RT_FONT);
878    if (!cfp) {
879	int aligned_id = stuff->id;
880	SendErrToClient(client, FSBadFont, (pointer) &aligned_id);
881	return FSBadFont;
882    }
883
884    /* get the header */
885    fsPack_XFontInfoHeader(&cfp->font->info, &reply, client->major_version);
886    err = convert_props(&cfp->font->info, &prop_info);
887
888    switch (err)
889    {
890    case Successful:
891	break;
892    case AllocError:
893	SendErrToClient(client, FSBadAlloc, (pointer) 0);
894	return err;
895    default:
896	ErrorF("ProcQueryXInfo: unexpected return val %d from convert_props\n",
897	       err);
898	SendErrToClient(client, FSBadImplementation, (pointer) 0);
899	return err;
900    }
901    lendata = SIZEOF(fsPropInfo) +
902	prop_info->num_offsets * SIZEOF(fsPropOffset) +
903	prop_info->data_len;
904
905    reply.length = (SIZEOF(fsQueryXInfoReply) + lendata + 3) >> 2;
906    WriteReplyToClient(client, SIZEOF(fsQueryXInfoReply), &reply);
907
908    if (client->swapped)
909	SwapPropInfo(prop_info);
910    (void) WriteToClient(client, lendata, (char *) prop_info);
911
912    fsfree((char *) prop_info);
913    return client->noClientException;
914}
915
916int
917ProcQueryXExtents(ClientPtr client)
918{
919    ClientFontPtr cfp;
920    int         err;
921    int         item_size;
922
923    REQUEST(fsQueryXExtents8Req);
924
925    REQUEST_AT_LEAST_SIZE(fsQueryXExtents8Req);
926
927    cfp = (ClientFontPtr) LookupIDByType(client->index, stuff->fid, RT_FONT);
928    if (!cfp) {
929	int aligned_fid = stuff->fid;
930	SendErrToClient(client, FSBadFont, (pointer) &aligned_fid);
931	return FSBadFont;
932    }
933    item_size = (stuff->reqType == FS_QueryXExtents8) ? 1 : 2;
934
935    if (stuff->num_ranges >
936	 ((stuff->length << 2) - SIZEOF(fsQueryXExtents8Req))/item_size) {
937	int num_ranges = stuff->num_ranges;
938	SendErrToClient(client, FSBadLength, (pointer)&num_ranges);
939	return FSBadLength;
940    }
941
942    /* get the extents */
943    err = QueryExtents(client, cfp, item_size,
944		       stuff->num_ranges, stuff->range,
945		       (char *)stuff + SIZEOF(fsQueryXExtents8Req));
946
947    if (err != FSSuccess) {
948	return err;
949    } else
950	return client->noClientException;
951}
952
953int
954ProcQueryXBitmaps(ClientPtr client)
955{
956    ClientFontPtr cfp;
957    int         err;
958    int         item_size;
959
960    REQUEST(fsQueryXBitmaps8Req);
961
962    REQUEST_AT_LEAST_SIZE(fsQueryXBitmaps8Req);
963
964    cfp = (ClientFontPtr) LookupIDByType(client->index, stuff->fid, RT_FONT);
965    if (!cfp) {
966	int aligned_fid = stuff->fid;
967	SendErrToClient(client, FSBadFont, (pointer) &aligned_fid);
968	return FSBadFont;
969    }
970    if (stuff->format & ~ALL_FORMAT_BITS) {
971	int aligned_format = stuff->format;
972	SendErrToClient(client, FSBadFormat, (pointer) &aligned_format);
973	return FSBadFormat;
974    }
975    assert((stuff->reqType == FS_QueryXBitmaps8) || (stuff->reqType == FS_QueryXBitmaps16));
976    item_size = (stuff->reqType == FS_QueryXBitmaps8) ? 1 : 2;
977
978    if (stuff->num_ranges >
979	((stuff->length << 2) - SIZEOF(fsQueryXBitmaps8Req))/item_size) {
980	int num_ranges = stuff->num_ranges;
981	SendErrToClient(client, FSBadLength, (pointer)&num_ranges);
982	return FSBadLength;
983    }
984    /* get the glyphs */
985    err = QueryBitmaps(client, cfp, item_size, stuff->format,
986		       stuff->num_ranges, stuff->range,
987		       (char *)stuff + SIZEOF(fsQueryXBitmaps8Req));
988
989    if (err != FSSuccess) {
990	return err;
991    } else {
992	return client->noClientException;
993    }
994}
995
996int
997ProcCloseFont(ClientPtr client)
998{
999    ClientFontPtr cfp;
1000
1001    REQUEST(fsResourceReq);
1002
1003    REQUEST_SIZE_MATCH(fsResourceReq);
1004    cfp = (ClientFontPtr) LookupIDByType(client->index, stuff->id, RT_FONT);
1005    if (cfp) {
1006	FreeResource(client->index, stuff->id, RT_NONE);
1007	return client->noClientException;
1008    } else {
1009	int aligned_id = stuff->id;
1010	SendErrToClient(client, FSBadFont, (pointer) &aligned_id);
1011	return FSBadFont;
1012    }
1013}
1014
1015void
1016DoCloseDownClient(ClientPtr client)
1017{
1018    if (client->clientGone != CLIENT_GONE) {
1019	DeleteClientFontStuff(client);
1020	client->clientGone = CLIENT_GONE;
1021	CloseDownConnection(client);
1022	--nClients;
1023    }
1024
1025    if (ClientIsAsleep(client))
1026	ClientSignal((pointer)client);
1027    else
1028    {
1029	FreeClientResources(client);
1030	if (client->index < nextFreeClientID)
1031	    nextFreeClientID = client->index;
1032	clients[client->index] = NullClient;
1033#ifdef DebugConnectionTranslation
1034	CheckFileNumbers();
1035#endif /* DebugConnectionTranslation */
1036
1037#ifdef NOTYET
1038	/* reset server when last client goes away */
1039	if (client->requestVector != InitialVector && nClients == 0)
1040	    dispatchException |= DE_RESET;
1041#endif
1042
1043	if (currentClient == client)
1044	    currentClient = serverClient;
1045	fsfree(client);
1046
1047#ifdef DEBUG
1048	fprintf(stderr, "Shut down client\n");
1049#endif
1050
1051	while (!clients[currentMaxClients - 1])
1052	    currentMaxClients--;
1053    }
1054}
1055
1056static void
1057kill_all_clients(void)
1058{
1059    int         i;
1060
1061    for (i = MINCLIENT; i < currentMaxClients; i++) {
1062	if (clients[i])
1063	    CloseDownClient(clients[i]);
1064    }
1065}
1066
1067void
1068InitProcVectors(void)
1069{
1070    int         i;
1071
1072    for (i = 0; i < NUM_PROC_VECTORS; i++) {
1073	if (!ProcVector[i]) {
1074	    ProcVector[i] = SwappedProcVector[i] = ProcBadRequest;
1075	    ReplySwapVector[i] = (ReplySwapFunc)NotImplemented;
1076	}
1077    }
1078    for (i = FSLASTEvent; i < NUM_EVENT_VECTORS; i++) {
1079	EventSwapVector[i] = (EventSwapFunc)NotImplemented;
1080    }
1081}
1082
1083void
1084InitClient(
1085    ClientPtr   client,
1086    int         i,
1087    pointer     ospriv)
1088{
1089    if (i != SERVER_CLIENT) {
1090	nClients++;
1091    }
1092    client->index = i;
1093    client->sequence = 0;
1094    client->last_request_time = GetTimeInMillis();
1095    client->clientGone = CLIENT_ALIVE;
1096    client->noClientException = FSSuccess;
1097    client->requestVector = InitialVector;
1098    client->osPrivate = ospriv;
1099    client->swapped = FALSE;
1100
1101    client->auth = (AuthContextPtr) 0;
1102    client->catalogues = NULL;
1103    client->num_catalogues = 0;
1104    client->num_resolutions = 0;
1105    client->resolutions = (fsResolution *) 0;
1106    client->eventmask = (Mask) 0;
1107}
1108
1109ClientPtr
1110NextAvailableClient(pointer ospriv)
1111{
1112    int         i;
1113    ClientPtr   client;
1114    fsFakeReq   data;
1115
1116    i = nextFreeClientID;
1117    if (i == MaxClients)
1118	return NullClient;
1119
1120    clients[i] = client = (ClientPtr) fsalloc(sizeof(ClientRec));
1121    if (!client)
1122	return NullClient;
1123
1124    InitClient(client, i, ospriv);
1125
1126    if (!InitClientResources(client)) {
1127	fsfree(client);
1128	return NullClient;
1129    }
1130    data.reqType = 1;
1131    data.length = (sizeof(fsFakeReq) + SIZEOF(fsConnClientPrefix)) >> 2;
1132    if (!InsertFakeRequest(client, (char *) &data, sizeof(fsFakeReq))) {
1133	FreeClientResources(client);
1134	fsfree(client);
1135	return NullClient;
1136    }
1137    if (i == currentMaxClients)
1138	currentMaxClients++;
1139    while ((nextFreeClientID < MAXCLIENTS) && clients[nextFreeClientID])
1140	nextFreeClientID++;
1141
1142    /* if we've maxed out, try to clone */
1143    if (nextFreeClientID == MaxClients) {
1144	CloneMyself();
1145    }
1146    return client;
1147}
1148
1149void
1150MarkClientException(ClientPtr client)
1151{
1152    client->noClientException = -2;
1153}
1154