dispatch.c revision e1db7cd1
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	    DEALLOCATE_LOCAL(client_auth);
257	    return (FSBadLength);
258	}
259	/* copy carefully in case wire data is not aligned */
260	client_auth[i].namelen = (((unsigned char *)ad)[0] << 8) +
261				 ((unsigned char *)ad)[1];
262	ad += 2;
263	client_auth[i].datalen = (((unsigned char *)ad)[0] << 8) +
264				 ((unsigned char *)ad)[1];
265	ad += 2;
266	client_auth[i].name = (char *) ad;
267	ad += client_auth[i].namelen;
268	client_auth[i].data = (char *) ad;
269	ad += client_auth[i].datalen;
270    }
271    if (!(int)prefix->num_auths)
272	ad += 4;
273    if (ad - (char *)auth_data > (stuff->length << 2)) {
274	int lengthword = stuff->length;
275
276	SendErrToClient(client, FSBadLength, (pointer)&lengthword);
277	DEALLOCATE_LOCAL(client_auth);
278	return (FSBadLength);
279    }
280
281    num_alts = ListAlternateServers(&altservers);
282    for (i = 0, altlen = 0; i < num_alts; i++) {
283	/* subset + len + namelen + pad */
284	altlen += (2 + altservers[i].namelen + 3) >> 2;
285    }
286
287    auth_index = prefix->num_auths;
288    client->auth_generation = 0;
289    ret = CheckClientAuthorization(client, client_auth,
290		    &auth_accept, &auth_index, &auth_len, &server_auth_data);
291    if (auth_index > 0)
292    {
293	AuthContextPtr authp;
294	authp = (AuthContextPtr) FSalloc(sizeof(AuthContextRec));
295	if (!authp) {
296	    SendErrToClient(client, FSBadAlloc, (pointer) 0);
297	    DEALLOCATE_LOCAL(client_auth);
298	    return FSBadAlloc;
299	}
300	authp->authname =
301	    (char *) FSalloc(client_auth[auth_index - 1].namelen + 1);
302	authp->authdata =
303	    (char *) FSalloc(client_auth[auth_index - 1].datalen + 1);
304	if (!authp->authname || !authp->authdata) {
305	    FSfree((char *) authp->authname);
306	    FSfree((char *) authp->authdata);
307	    FSfree((char *) authp);
308	    SendErrToClient(client, FSBadAlloc, (pointer) 0);
309	    DEALLOCATE_LOCAL(client_auth);
310	    return FSBadAlloc;
311	}
312	memcpy(authp->authname, client_auth[auth_index - 1].name,
313	      client_auth[auth_index - 1].namelen);
314	memcpy(authp->authdata, client_auth[auth_index - 1].data,
315	      client_auth[auth_index - 1].datalen);
316	/* Save it with a zero resource id...  subsequent
317	   SetAuthorizations of None will find it.  And it will be freed
318	   by FreeClientResources when the connection closes.  */
319	if (!AddResource(client->index, 0, RT_AUTHCONT,(pointer) authp))
320	{
321	    FSfree((char *) authp->authname);
322	    FSfree((char *) authp->authdata);
323	    FSfree((char *) authp);
324	    SendErrToClient(client, FSBadAlloc, (pointer) 0);
325	    DEALLOCATE_LOCAL(client_auth);
326	    return FSBadAlloc;
327	}
328	client->auth = client->default_auth = authp;
329    }
330    else
331	client->auth = client->default_auth = (AuthContextPtr)0;
332
333    DEALLOCATE_LOCAL(client_auth);
334
335    if (ret != FSSuccess) {
336	SendErrToClient(client, FSBadAlloc, (pointer) 0);
337	return FSBadAlloc;
338    }
339    else {
340	fsConnSetup csp = {
341	    .status = auth_accept,
342	    /* we implement backwards compatibility for version 1.0 */
343	    .major_version = (client->major_version == 1) ?
344	        client->major_version : FS_PROTOCOL,
345	    .minor_version = FS_PROTOCOL_MINOR,
346	    .num_alternates = num_alts,
347	    .alternate_len = altlen,
348	    .auth_len = auth_len >> 2,
349	    .auth_index = auth_index
350	};
351	if (client->swapped) {
352	    WriteSConnSetup(client, &csp);
353	} else {
354	    (void) WriteToClient(client, SIZEOF(fsConnSetup), (char *) &csp);
355	}
356    }
357
358    /* send the alternates info */
359    for (i = 0; i < num_alts; i++) {
360	char        tmp[258];
361
362	/* WriteToClient pads, so we have to fake some things */
363	tmp[0] = altservers[i].subset;
364	tmp[1] = altservers[i].namelen;
365	memcpy(&tmp[2], altservers[i].name, altservers[i].namelen);
366	(void) WriteToClient(client, altservers[i].namelen + 2, tmp);
367    }
368
369    if (auth_len)
370	(void) WriteToClient(client, auth_len, (char *) server_auth_data);
371
372    if (auth_accept != AuthSuccess) {
373	nClients--;
374	return (client->noClientException = -2);
375    }
376    client->requestVector = client->swapped ? SwappedProcVector : ProcVector;
377    client->sequence = 0;
378    if (client->swapped)
379	(void) WriteSConnectionInfo(client, ConnInfoLen, ConnectionInfo);
380    else
381	(void) WriteToClient(client, ConnInfoLen, ConnectionInfo);
382
383#ifdef DEBUG
384    fprintf(stderr, "Establishing new connection\n");
385#endif
386
387    return client->noClientException;
388}
389
390/*
391 * NOTE -- the incoming data may be mangled
392 */
393
394void
395DoSendErrToClient(
396    ClientPtr   client,
397    int         error,
398    pointer     data)		/* resource id, format, resolution, etc */
399{
400    fsError     rep = {
401	.type = FS_Error,
402	.request = error,
403	.sequenceNumber = client->sequence,
404	.timestamp = GetTimeInMillis(),
405	.major_opcode = ((fsReq *) client->requestBuffer)->reqType,
406	.minor_opcode = 0
407    };
408    int         extralen = 0;
409
410    switch (error) {
411    case FSBadFormat:
412	extralen = SIZEOF(fsBitmapFormat);
413	break;
414    case FSBadFont:
415    case FSBadAccessContext:
416    case FSBadIDChoice:
417    case FSBadEventMask:
418	if (data) {
419	    if (client->swapped)
420	        SwapLongs((long *) data, 1);
421	    extralen = 4;
422	}
423	break;
424    case FSBadRange:
425	extralen = SIZEOF(fsRange);
426	break;
427    case FSBadResolution:
428	if (data) {
429	    if (client->swapped)
430	        SwapShorts((short *) data, 1);
431	    /* note sneaky hack */
432	    rep.pad = *(CARD16 *) data;
433	    data = (char *)data + 2;
434	    extralen = 4;
435	}
436	break;
437    case FSBadLength:
438	if (data) {
439	    if (client->swapped)
440	        SwapLongs((long *) data, 1);
441	    extralen = 4;
442	}
443	break;
444    default:
445	/* nothing else to send */
446	break;
447    }
448
449    rep.length = (SIZEOF(fsError) + extralen) >> 2;
450
451    WriteErrorToClient(client, &rep);
452
453    if (extralen)
454	WriteToClient(client, extralen, (char *) data);
455}
456
457/* ARGSUSED */
458int
459ProcBadRequest(ClientPtr client)
460{
461    SendErrToClient(client, FSBadRequest, NULL);
462    return FSBadRequest;
463}
464
465int
466ProcNoop(ClientPtr client)
467{
468    REQUEST(fsReq);
469    REQUEST_AT_LEAST_SIZE(fsReq);
470
471    return client->noClientException;
472}
473
474int
475ProcListCatalogues(ClientPtr client)
476{
477    int         len,
478                num;
479    char       *catalogues;
480    fsListCataloguesReply rep = {
481	.type = FS_Reply,
482	.sequenceNumber = client->sequence,
483	.num_replies = 0
484    };
485
486    REQUEST(fsListCataloguesReq);
487    REQUEST_AT_LEAST_SIZE(fsListCataloguesReq);
488
489    num = ListCatalogues((char *)stuff + SIZEOF(fsListCataloguesReq),
490			 stuff->nbytes, stuff->maxNames,
491			 &catalogues, &len);
492    rep.num_catalogues = num;
493    rep.length = (SIZEOF(fsListCataloguesReply) + len + 3) >> 2;
494
495    WriteReplyToClient(client, SIZEOF(fsListCataloguesReply), &rep);
496    (void) WriteToClient(client, len, (char *) catalogues);
497    FSfree((char *) catalogues);
498    return client->noClientException;
499}
500
501int
502ProcSetCatalogues(ClientPtr client)
503{
504    char       *new_cat;
505    int         err,
506                len;
507    int         num;
508
509    REQUEST(fsSetCataloguesReq);
510    REQUEST_AT_LEAST_SIZE(fsSetCataloguesReq);
511
512    if (stuff->num_catalogues == 0) {
513	/* use the default */
514	num = ListCatalogues("*", 1, 10000, &new_cat, &len);
515    } else {
516	num = stuff->num_catalogues;
517	err = ValidateCatalogues(&num, (char *)stuff + SIZEOF(fsSetCataloguesReq));
518	if (err == FSSuccess) {
519	    len = (stuff->length << 2) - SIZEOF(fsSetCataloguesReq);
520	    new_cat = (char *) FSalloc(len);
521	    if (!new_cat)
522		return FSBadAlloc;
523	    memcpy(new_cat, (char *)stuff + SIZEOF(fsSetCataloguesReq), len);
524	} else {
525	    SendErrToClient(client, err, (pointer) &num);
526	    return err;
527	}
528    }
529    if (client->catalogues)
530	FSfree((char *) client->catalogues);
531    client->catalogues = new_cat;
532    client->num_catalogues = num;
533    return client->noClientException;
534}
535
536int
537ProcGetCatalogues(ClientPtr client)
538{
539    int         len,
540                i,
541                size;
542    char       *cp;
543
544    REQUEST(fsGetCataloguesReq);
545    REQUEST_AT_LEAST_SIZE(fsGetCataloguesReq);
546
547    for (i = 0, len = 0, cp = client->catalogues;
548	    i < client->num_catalogues; i++) {
549	size = *cp++;
550	len += size + 1;	/* str length + size byte */
551	cp += size;
552    }
553
554    {
555        fsGetCataloguesReply rep = {
556	    .type = FS_Reply,
557	    .num_catalogues = client->num_catalogues,
558	    .sequenceNumber = client->sequence,
559	    .length = (SIZEOF(fsGetCataloguesReply) + len + 3) >> 2
560	};
561
562	WriteReplyToClient(client, SIZEOF(fsGetCataloguesReply), &rep);
563    }
564    (void) WriteToClient(client, len, client->catalogues);
565
566    return client->noClientException;
567}
568
569int
570ProcCreateAC(ClientPtr client)
571{
572    AuthPtr     acp;
573    AuthContextPtr authp;
574    int         accept,
575                i,
576                err,
577                index,
578                size;
579    char       *ad;
580    char       *auth_data;
581
582    REQUEST(fsCreateACReq);
583    REQUEST_AT_LEAST_SIZE(fsCreateACReq);
584
585    authp = (AuthContextPtr) LookupIDByType(client->index, stuff->acid,
586					    RT_AUTHCONT);
587    if (authp) {
588	int aligned_acid = stuff->acid;
589	SendErrToClient(client, FSBadIDChoice, (pointer) &aligned_acid);
590	return FSBadIDChoice;
591    }
592    acp = NULL;
593    if (stuff->num_auths)
594    {
595    	acp = (AuthPtr) ALLOCATE_LOCAL(stuff->num_auths * sizeof(AuthRec));
596    	if (!acp) {
597	    SendErrToClient(client, FSBadAlloc, (pointer) NULL);
598	    return FSBadAlloc;
599    	}
600    }
601    /* build up a list of the stuff */
602    for (i = 0, ad = (char *)stuff + SIZEOF(fsCreateACReq);
603         i < (int)stuff->num_auths; i++) {
604	if (ad - (char *)stuff + SIZEOF(fsCreateACReq) >
605	    (stuff->length << 2) - 4) {
606	    int lengthword = stuff->length;
607
608	    SendErrToClient(client, FSBadLength, (pointer)&lengthword);
609	    DEALLOCATE_LOCAL(acp);
610	    return (FSBadLength);
611	}
612	/* copy carefully in case data is not aligned */
613	acp[i].namelen = (((unsigned char *)ad)[0] << 8) +
614			 ((unsigned char *)ad)[1];
615	ad += 2;
616	acp[i].datalen = (((unsigned char *)ad)[0] << 8) +
617			 ((unsigned char *)ad)[1];
618	ad += 2;
619	acp[i].name = (char *) ad;
620	ad += acp[i].namelen;
621	acp[i].data = (char *) ad;
622	ad += acp[i].datalen;
623    }
624    if (ad - (char *)stuff > (stuff->length << 2)) {
625	int lengthword = stuff->length;
626
627	SendErrToClient(client, FSBadLength, (pointer)&lengthword);
628	if (acp)
629	    DEALLOCATE_LOCAL(acp);
630	return (FSBadLength);
631    }
632
633/* XXX needs work for AuthContinue */
634    index = stuff->num_auths;
635    err = CheckClientAuthorization(client, acp, &accept, &index, &size,
636				   &auth_data);
637
638    if (err != FSSuccess) {
639	SendErrToClient(client, err, (pointer) 0);
640	if (acp)
641	    DEALLOCATE_LOCAL(acp);
642	return err;
643    }
644    authp = (AuthContextPtr) FSalloc(sizeof(AuthContextRec));
645    if (!authp) {
646	goto alloc_failure;
647    }
648    authp->authname = NULL;
649    authp->authdata = NULL;
650    if (index > 0)
651    {
652	authp->authname = (char *) FSalloc(acp[index - 1].namelen + 1);
653	authp->authdata = (char *) FSalloc(acp[index - 1].datalen + 1);
654	if (!authp->authname || !authp->authdata) {
655	    FSfree((char *) authp->authname);
656	    FSfree((char *) authp->authdata);
657	    FSfree((char *) authp);
658	    goto alloc_failure;
659	}
660	memcpy(authp->authname, acp[index - 1].name, acp[index - 1].namelen);
661	memcpy(authp->authdata, acp[index - 1].data, acp[index - 1].datalen);
662    }
663    else
664	size = 0;
665    authp->acid = stuff->acid;
666    if (!AddResource(client->index, stuff->acid, RT_AUTHCONT,(pointer) authp))
667    {
668alloc_failure:
669	SendErrToClient(client, FSBadAlloc, (pointer) 0);
670	if (acp)
671	    DEALLOCATE_LOCAL(acp);
672	return FSBadAlloc;
673    }
674    DEALLOCATE_LOCAL(acp);
675    {
676        fsCreateACReply rep = {
677	    .type = FS_Reply,
678	    .auth_index = index,
679	    .sequenceNumber = client->sequence,
680	    .status = accept,
681	    .length = (SIZEOF(fsCreateACReply) + size) >> 2
682	};
683
684	WriteReplyToClient(client, SIZEOF(fsCreateACReply), &rep);
685    }
686    if (size)
687	(void) WriteToClient(client, size, auth_data);
688
689    return client->noClientException;
690}
691
692/* ARGSUSED */
693int
694DeleteAuthCont (pointer value, FSID id)
695{
696    AuthContextPtr  authp = (AuthContextPtr) value;
697
698    if (authp->authname)
699	FSfree (authp->authname);
700    if (authp->authdata)
701	FSfree (authp->authdata);
702    FSfree (authp);
703    return 1;
704}
705
706int
707ProcFreeAC(ClientPtr client)
708{
709    AuthContextPtr authp;
710
711    REQUEST(fsFreeACReq);
712    REQUEST_AT_LEAST_SIZE(fsFreeACReq);
713    authp = (AuthContextPtr) LookupIDByType(client->index, stuff->id,
714					  RT_AUTHCONT);
715    if (!authp) {
716	int aligned_id = stuff->id;
717	SendErrToClient(client, FSBadIDChoice, (pointer) &aligned_id);
718	return FSBadIDChoice;
719    }
720    if (client->auth == authp)
721	client->auth = client->default_auth;
722    FreeResource(client->index, stuff->id, RT_NONE);
723    return client->noClientException;
724}
725
726int
727ProcSetAuthorization(ClientPtr client)
728{
729    AuthContextPtr acp;
730
731    REQUEST(fsSetAuthorizationReq);
732    REQUEST_AT_LEAST_SIZE(fsSetAuthorizationReq);
733    acp = (AuthContextPtr) LookupIDByType(client->index, stuff->id,
734					  RT_AUTHCONT);
735    if (!acp) {
736	int aligned_id = stuff->id;
737	SendErrToClient(client, FSBadIDChoice, (pointer) &aligned_id);
738	return FSBadIDChoice;
739    }
740    client->auth = acp;		/* XXX does this need a refcount? */
741    return client->noClientException;
742}
743
744int
745ProcSetResolution(ClientPtr client)
746{
747    fsResolution *new_res;
748
749    REQUEST(fsSetResolutionReq);
750    REQUEST_AT_LEAST_SIZE(fsSetResolutionReq);
751
752    if ((stuff->length << 2) - SIZEOF(fsSetResolutionReq) <
753        stuff->num_resolutions * SIZEOF(fsResolution)) {
754	int lengthword = stuff->length;
755
756	SendErrToClient(client, FSBadLength, &lengthword);
757	return FSBadLength;
758    }
759    new_res = (fsResolution *)
760	FSallocarray(stuff->num_resolutions, SIZEOF(fsResolution));
761    if (!new_res) {
762	SendErrToClient(client, FSBadAlloc, NULL);
763	return FSBadAlloc;
764    }
765    FSfree((char *) client->resolutions);
766    memcpy(new_res, (char *)stuff + SIZEOF(fsSetResolutionReq),
767	  (stuff->num_resolutions * SIZEOF(fsResolution)));
768    client->resolutions = new_res;
769    client->num_resolutions = stuff->num_resolutions;
770
771    return client->noClientException;
772}
773
774int
775ProcGetResolution(ClientPtr client)
776{
777    REQUEST(fsReq);
778    REQUEST_AT_LEAST_SIZE(fsReq);
779
780    if ((stuff->length << 2) - SIZEOF(fsResolution) < client->num_resolutions *
781	sizeof(fsResolution)) {
782	int lengthword = stuff->length;
783
784	SendErrToClient(client, FSBadLength, &lengthword);
785	return FSBadLength;
786    }
787    else {
788	fsGetResolutionReply reply = {
789	    .type = FS_Reply,
790	    .num_resolutions = client->num_resolutions,
791	    .sequenceNumber = client->sequence,
792	    .length = (SIZEOF(fsGetResolutionReply) +
793		       client->num_resolutions * SIZEOF(fsResolution)) >> 2
794	};
795
796	WriteReplyToClient(client, SIZEOF(fsGetResolutionReply), &reply);
797    }
798    if (client->swapped)
799	client->pSwapReplyFunc = CopySwap16Write;
800
801    WriteSwappedDataToClient(client,
802       (client->num_resolutions * SIZEOF(fsResolution)), (short *)client->resolutions);
803
804    return client->noClientException;
805}
806
807int
808ProcListFonts(ClientPtr client)
809{
810    REQUEST(fsListFontsReq);
811    REQUEST_FIXED_SIZE(fsListFontsReq, stuff->nbytes);
812
813    return ListFonts(client, stuff->nbytes,
814		     (unsigned char *)stuff + SIZEOF(fsListFontsReq),
815		     stuff->maxNames);
816}
817
818int
819ProcListFontsWithXInfo(ClientPtr client)
820{
821    REQUEST(fsListFontsWithXInfoReq);
822    REQUEST_FIXED_SIZE(fsListFontsWithXInfoReq, stuff->nbytes);
823
824    return StartListFontsWithInfo(client, stuff->nbytes,
825				  (unsigned char *)stuff + SIZEOF(fsListFontsWithXInfoReq), stuff->maxNames);
826}
827
828int
829ProcOpenBitmapFont(ClientPtr client)
830{
831    FontPtr     pfont;
832    int         nbytes,
833                err;
834    unsigned char *fname;
835
836    REQUEST(fsOpenBitmapFontReq);
837    fname = (unsigned char *)stuff + SIZEOF(fsOpenBitmapFontReq);
838    nbytes = *fname++;
839
840    REQUEST_FIXED_SIZE(fsOpenBitmapFontReq, (nbytes + 1));
841
842    pfont = (FontPtr) LookupIDByType(client->index, stuff->fid, RT_FONT);
843    if (pfont) {
844	int aligned_fid = stuff->fid;
845	SendErrToClient(client, FSBadIDChoice, (pointer) &aligned_fid);
846	return FSBadIDChoice;
847    }
848    if (stuff->format_hint != 0 &&
849	    stuff->format_hint & ~ALL_FORMAT_BITS) {
850	int aligned_format_hint = stuff->format_hint;
851	SendErrToClient(client, FSBadFormat, (pointer) &aligned_format_hint);
852	return FSBadFormat;
853    }
854    if (stuff->format_mask & ~ALL_FORMAT_MASK_BITS) {
855	int aligned_format_mask = stuff->format_mask;
856	SendErrToClient(client, FSBadFormat, (pointer) &aligned_format_mask);
857	return FSBadFormat;
858    }
859    err = OpenFont(client, stuff->fid, stuff->format_hint, stuff->format_mask,
860		   nbytes, (char *) fname);
861
862    if (err == FSSuccess) {
863	return client->noClientException;
864    } else {
865	return err;
866    }
867}
868
869int
870ProcQueryXInfo(ClientPtr client)
871{
872    ClientFontPtr cfp;
873    int         err,
874                lendata;
875    fsQueryXInfoReply reply = {
876	.type = FS_Reply,
877	.sequenceNumber = client->sequence
878    };
879    fsPropInfo *prop_info;
880
881    REQUEST(fsQueryXInfoReq);
882
883    REQUEST_AT_LEAST_SIZE(fsQueryXInfoReq);
884
885    cfp = (ClientFontPtr) LookupIDByType(client->index, stuff->id, RT_FONT);
886    if (!cfp) {
887	int aligned_id = stuff->id;
888	SendErrToClient(client, FSBadFont, (pointer) &aligned_id);
889	return FSBadFont;
890    }
891
892    /* get the header */
893    fsPack_XFontInfoHeader(&cfp->font->info, &reply, client->major_version);
894    err = convert_props(&cfp->font->info, &prop_info);
895
896    switch (err)
897    {
898    case Successful:
899	break;
900    case AllocError:
901	SendErrToClient(client, FSBadAlloc, (pointer) 0);
902	return err;
903    default:
904	ErrorF("ProcQueryXInfo: unexpected return val %d from convert_props\n",
905	       err);
906	SendErrToClient(client, FSBadImplementation, (pointer) 0);
907	return err;
908    }
909    lendata = SIZEOF(fsPropInfo) +
910	prop_info->num_offsets * SIZEOF(fsPropOffset) +
911	prop_info->data_len;
912
913    reply.length = (SIZEOF(fsQueryXInfoReply) + lendata + 3) >> 2;
914    WriteReplyToClient(client, SIZEOF(fsQueryXInfoReply), &reply);
915
916    if (client->swapped)
917	SwapPropInfo(prop_info);
918    (void) WriteToClient(client, lendata, (char *) prop_info);
919
920    FSfree((char *) prop_info);
921    return client->noClientException;
922}
923
924int
925ProcQueryXExtents(ClientPtr client)
926{
927    ClientFontPtr cfp;
928    int         err;
929    int         item_size;
930
931    REQUEST(fsQueryXExtents8Req);
932
933    REQUEST_AT_LEAST_SIZE(fsQueryXExtents8Req);
934
935    cfp = (ClientFontPtr) LookupIDByType(client->index, stuff->fid, RT_FONT);
936    if (!cfp) {
937	int aligned_fid = stuff->fid;
938	SendErrToClient(client, FSBadFont, (pointer) &aligned_fid);
939	return FSBadFont;
940    }
941    item_size = (stuff->reqType == FS_QueryXExtents8) ? 1 : 2;
942
943    if (stuff->num_ranges >
944	 ((stuff->length << 2) - SIZEOF(fsQueryXExtents8Req))/item_size) {
945	int num_ranges = stuff->num_ranges;
946	SendErrToClient(client, FSBadLength, (pointer)&num_ranges);
947	return FSBadLength;
948    }
949
950    /* get the extents */
951    err = QueryExtents(client, cfp, item_size,
952		       stuff->num_ranges, stuff->range,
953		       (char *)stuff + SIZEOF(fsQueryXExtents8Req));
954
955    if (err != FSSuccess) {
956	return err;
957    } else
958	return client->noClientException;
959}
960
961int
962ProcQueryXBitmaps(ClientPtr client)
963{
964    ClientFontPtr cfp;
965    int         err;
966    int         item_size;
967
968    REQUEST(fsQueryXBitmaps8Req);
969
970    REQUEST_AT_LEAST_SIZE(fsQueryXBitmaps8Req);
971
972    cfp = (ClientFontPtr) LookupIDByType(client->index, stuff->fid, RT_FONT);
973    if (!cfp) {
974	int aligned_fid = stuff->fid;
975	SendErrToClient(client, FSBadFont, (pointer) &aligned_fid);
976	return FSBadFont;
977    }
978    if (stuff->format & ~ALL_FORMAT_BITS) {
979	int aligned_format = stuff->format;
980	SendErrToClient(client, FSBadFormat, (pointer) &aligned_format);
981	return FSBadFormat;
982    }
983    assert((stuff->reqType == FS_QueryXBitmaps8) || (stuff->reqType == FS_QueryXBitmaps16));
984    item_size = (stuff->reqType == FS_QueryXBitmaps8) ? 1 : 2;
985
986    if (stuff->num_ranges >
987	((stuff->length << 2) - SIZEOF(fsQueryXBitmaps8Req))/item_size) {
988	int num_ranges = stuff->num_ranges;
989	SendErrToClient(client, FSBadLength, (pointer)&num_ranges);
990	return FSBadLength;
991    }
992    /* get the glyphs */
993    err = QueryBitmaps(client, cfp, item_size, stuff->format,
994		       stuff->num_ranges, stuff->range,
995		       (char *)stuff + SIZEOF(fsQueryXBitmaps8Req));
996
997    if (err != FSSuccess) {
998	return err;
999    } else {
1000	return client->noClientException;
1001    }
1002}
1003
1004int
1005ProcCloseFont(ClientPtr client)
1006{
1007    ClientFontPtr cfp;
1008
1009    REQUEST(fsResourceReq);
1010
1011    REQUEST_SIZE_MATCH(fsResourceReq);
1012    cfp = (ClientFontPtr) LookupIDByType(client->index, stuff->id, RT_FONT);
1013    if (cfp) {
1014	FreeResource(client->index, stuff->id, RT_NONE);
1015	return client->noClientException;
1016    } else {
1017	int aligned_id = stuff->id;
1018	SendErrToClient(client, FSBadFont, (pointer) &aligned_id);
1019	return FSBadFont;
1020    }
1021}
1022
1023void
1024DoCloseDownClient(ClientPtr client)
1025{
1026    if (client->clientGone != CLIENT_GONE) {
1027	DeleteClientFontStuff(client);
1028	client->clientGone = CLIENT_GONE;
1029	CloseDownConnection(client);
1030	--nClients;
1031    }
1032
1033    if (ClientIsAsleep(client))
1034	ClientSignal((pointer)client);
1035    else
1036    {
1037	FreeClientResources(client);
1038	if (client->index < nextFreeClientID)
1039	    nextFreeClientID = client->index;
1040	clients[client->index] = NullClient;
1041#ifdef DebugConnectionTranslation
1042	CheckFileNumbers();
1043#endif /* DebugConnectionTranslation */
1044
1045
1046	if (currentClient == client)
1047	    currentClient = serverClient;
1048	FSfree(client);
1049
1050#ifdef DEBUG
1051	fprintf(stderr, "Shut down client\n");
1052#endif
1053
1054	while (!clients[currentMaxClients - 1])
1055	    currentMaxClients--;
1056    }
1057}
1058
1059static void
1060kill_all_clients(void)
1061{
1062    int         i;
1063
1064    for (i = MINCLIENT; i < currentMaxClients; i++) {
1065	if (clients[i])
1066	    CloseDownClient(clients[i]);
1067    }
1068}
1069
1070void
1071InitProcVectors(void)
1072{
1073    int         i;
1074
1075    for (i = 0; i < NUM_PROC_VECTORS; i++) {
1076	if (!ProcVector[i]) {
1077	    ProcVector[i] = SwappedProcVector[i] = ProcBadRequest;
1078	    ReplySwapVector[i] = ReplySwapNotImplemented;
1079	}
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