1/*
2
3Copyright 1993, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25*/
26
27/*
28 * Author: Ralph Mor, X Consortium
29 */
30
31#ifdef HAVE_CONFIG_H
32#include <config.h>
33#endif
34#include <X11/SM/SMlib.h>
35#include <limits.h>
36#include "SMlibint.h"
37
38
39/*
40 * Check for bad length
41 */
42
43#define CHECK_SIZE_MATCH(_iceConn, _majorOp, _minorOp, _expected_len, _actual_len, _severity) \
44    if ((((_actual_len) - SIZEOF (iceMsg)) >> 3) != _expected_len) \
45    { \
46       _IceErrorBadLength (_iceConn, _majorOp, _minorOp, _severity); \
47       return; \
48    }
49
50#define CHECK_AT_LEAST_SIZE(_iceConn, _majorOp, _minorOp, _expected_len, _actual_len, _severity) \
51    if ((((_actual_len) - SIZEOF (iceMsg)) >> 3) > _expected_len) \
52    { \
53       _IceErrorBadLength (_iceConn, _majorOp, _minorOp, _severity); \
54       return; \
55    }
56
57
58static char *
59extractArray8(char **pBuf, char *pEnd, Bool swap, int *len)
60{
61    char	*p;
62    int		n;
63
64    if (pEnd - *pBuf < 4)
65	return NULL;
66    EXTRACT_CARD32 (*pBuf, swap, n);
67    if (n < 0 || n > INT_MAX - 7)
68	return NULL;
69
70    if ((p = malloc (n + 1)) == NULL)
71	return NULL;
72    memcpy(p, *pBuf, n);
73    p[n] = '\0';
74
75    *pBuf += n + PAD64 (4 + n);
76    if (len != NULL)
77	*len = n;
78
79    return p;
80}
81
82
83static SmProp **
84extractListofProperty(char *pBuf, char *pEnd, Bool swap, int *count)
85{
86    int		i, j, n;
87    SmProp	**props;
88
89    if (pEnd - pBuf < 4)
90	return NULL;
91    EXTRACT_CARD32 (pBuf, swap, n);
92    if (n < 0 || n > INT_MAX / sizeof (SmProp *))
93	return NULL;
94    pBuf += 4;
95
96    props = malloc (n * sizeof(SmProp *));
97    if (props == NULL)
98	return NULL;
99
100    for (i = 0; i < n; i++)
101    {
102	props[i] = calloc (1, sizeof (SmProp));
103	if (props[i] == NULL)
104	    goto fail;
105	if ((props[i]->name = extractArray8 (&pBuf, pEnd, swap, NULL)) == NULL)
106	    goto fail;
107	if ((props[i]->type = extractArray8 (&pBuf, pEnd, swap, NULL)) == NULL)
108	    goto fail;
109
110	if (pEnd - pBuf < 4)
111	    goto fail;
112	EXTRACT_CARD32 (pBuf, swap, props[i]->num_vals);
113	if (props[i]->num_vals < 0)
114	    goto fail;
115	pBuf += 4;
116	props[i]->vals = calloc (props[i]->num_vals, sizeof (SmPropValue));
117	if (props[i]->vals == NULL)
118	    goto fail;
119
120	for (j = 0; j < props[i]->num_vals; j++)
121	{
122	    props[i]->vals[j].value = extractArray8 (&pBuf, pEnd, swap,
123		&props[i]->vals[j].length);
124	    if (props[i]->vals[j].value == NULL)
125		goto fail;
126	}
127    }
128
129    *count = n;
130    return props;
131
132fail:
133    for (; i >= 0; i--)
134    {
135	if (props[i] != NULL)
136	{
137	    free (props[i]->name);
138	    free (props[i]->type);
139	    if (props[i]->vals != NULL)
140	    {
141		for (j = 0; j < props[i]->num_vals; j++)
142		    free (props[i]->vals[j].value);
143		free (props[i]->vals);
144	    }
145	    free (props[i]);
146	}
147    }
148    free (props);
149    return NULL;
150}
151
152
153static Bool
154validErrorMessage(char *pData, char *pEnd, int errorClass, Bool swap)
155{
156    if (errorClass == IceBadValue)
157    {
158	unsigned int length;
159
160	if (pEnd - pData < 8)
161	    return False;
162
163	pData += 4;
164	EXTRACT_CARD32 (pData, swap, length);
165	if (length > pEnd - pData)
166	    return False;
167    }
168
169    return True;
170}
171
172
173void
174_SmcProcessMessage(IceConn iceConn, IcePointer clientData, int opcode,
175		   unsigned long length, Bool swap,
176		   IceReplyWaitInfo *replyWait, Bool *replyReadyRet)
177{
178    SmcConn	smcConn = (SmcConn) clientData;
179
180    if (replyWait)
181	*replyReadyRet = False;
182
183    if (!smcConn->client_id &&
184        opcode != SM_RegisterClientReply && opcode != SM_Error)
185    {
186	_IceReadSkip (iceConn, length << 3);
187
188	_IceErrorBadState (iceConn, _SmcOpcode, opcode, IceFatalToProtocol);
189	return;
190    }
191
192    switch (opcode)
193    {
194    case SM_Error:
195    {
196	iceErrorMsg 	*pMsg;
197	char	    	*pData, *pEnd;
198
199	CHECK_AT_LEAST_SIZE (iceConn, _SmcOpcode, opcode,
200	    length, SIZEOF (iceErrorMsg), IceFatalToProtocol);
201
202	IceReadCompleteMessage (iceConn, SIZEOF (iceErrorMsg),
203	    iceErrorMsg, pMsg, pData);
204
205	if (!IceValidIO (iceConn) || pData == NULL)
206	{
207	    IceDisposeCompleteMessage (iceConn, pData);
208	    return;
209	}
210
211	if (swap)
212	{
213	    pMsg->errorClass = lswaps (pMsg->errorClass);
214	    pMsg->offendingSequenceNum = lswapl (pMsg->offendingSequenceNum);
215	}
216
217	pEnd = pData + (length << 3) - (SIZEOF (iceErrorMsg) - SIZEOF(iceMsg));
218
219	if (replyWait &&
220	    replyWait->minor_opcode_of_request == SM_RegisterClient &&
221            pMsg->errorClass == IceBadValue &&
222	    pMsg->offendingMinorOpcode == SM_RegisterClient &&
223	    pMsg->offendingSequenceNum == replyWait->sequence_of_request)
224	{
225	    /*
226	     * For Register Client, the previous ID was bad.
227	     */
228
229	    _SmcRegisterClientReply *reply =
230		(_SmcRegisterClientReply *) (replyWait->reply);
231
232	    reply->status = 0;
233
234	    *replyReadyRet = True;
235	}
236	else if (!validErrorMessage(pData, pEnd, pMsg->errorClass, swap))
237	{
238	    _IceErrorBadLength (iceConn, _SmcOpcode, opcode,
239		IceFatalToProtocol);
240	    IceDisposeCompleteMessage (iceConn, pData);
241	    return;
242	}
243	else
244	{
245	    (*_SmcErrorHandler) (smcConn, swap,
246		pMsg->offendingMinorOpcode,
247	        pMsg->offendingSequenceNum,
248		pMsg->errorClass, pMsg->severity,
249		(SmPointer) pData);
250	}
251
252	IceDisposeCompleteMessage (iceConn, pData);
253	break;
254    }
255
256    case SM_RegisterClientReply:
257
258	if (!replyWait ||
259	    replyWait->minor_opcode_of_request != SM_RegisterClient)
260	{
261	    _IceReadSkip (iceConn, length << 3);
262
263	    _IceErrorBadState (iceConn, _SmcOpcode,
264		SM_RegisterClientReply, IceFatalToProtocol);
265	}
266        else
267	{
268	    smRegisterClientReplyMsg 	*pMsg;
269	    char			*pData, *pStart, *pEnd;
270	    _SmcRegisterClientReply 	*reply =
271	        (_SmcRegisterClientReply *) (replyWait->reply);
272
273	    CHECK_AT_LEAST_SIZE (iceConn, _SmcOpcode, opcode,
274		length, SIZEOF (smRegisterClientReplyMsg), IceFatalToProtocol);
275
276	    IceReadCompleteMessage (iceConn, SIZEOF (smRegisterClientReplyMsg),
277		smRegisterClientReplyMsg, pMsg, pStart);
278
279	    if (!IceValidIO (iceConn) || pStart == NULL)
280	    {
281		IceDisposeCompleteMessage (iceConn, pStart);
282		return;
283	    }
284
285	    pData = pStart;
286	    pEnd = pStart + (length << 3) -
287		(SIZEOF (smRegisterClientReplyMsg) - SIZEOF (iceMsg));
288
289	    reply->client_id = extractArray8(&pData, pEnd, swap, NULL);
290	    if (reply->client_id == NULL) {
291		_IceErrorBadLength (iceConn, _SmcOpcode, opcode,
292		    IceFatalToProtocol);
293		IceDisposeCompleteMessage (iceConn, pStart);
294		return;
295	    }
296
297	    reply->status = 1;
298	    *replyReadyRet = True;
299
300	    IceDisposeCompleteMessage (iceConn, pStart);
301	}
302	break;
303
304    case SM_SaveYourself:
305    {
306	smSaveYourselfMsg 	*pMsg;
307	unsigned char		errVal;
308	int			errOffset = -1;
309
310	CHECK_SIZE_MATCH (iceConn, _SmcOpcode, opcode,
311	    length, SIZEOF (smSaveYourselfMsg),
312	    IceFatalToProtocol);
313
314	IceReadMessageHeader (iceConn, SIZEOF (smSaveYourselfMsg),
315	    smSaveYourselfMsg, pMsg);
316
317	if (!IceValidIO (iceConn))
318	{
319	    return;
320	}
321
322	if (pMsg->saveType != SmSaveGlobal &&
323	    pMsg->saveType != SmSaveLocal &&
324	    pMsg->saveType != SmSaveBoth)
325	{
326	    errVal = pMsg->saveType;
327	    errOffset = 8;
328	}
329	else if (pMsg->shutdown != 1 && pMsg->shutdown != 0)
330	{
331	    errVal = pMsg->shutdown;
332	    errOffset = 9;
333	}
334	else if (pMsg->interactStyle != SmInteractStyleNone &&
335	    pMsg->interactStyle != SmInteractStyleErrors &&
336	    pMsg->interactStyle != SmInteractStyleAny)
337	{
338	    errVal = pMsg->interactStyle;
339	    errOffset = 10;
340	}
341	else if (pMsg->fast != 1 && pMsg->fast != 0)
342	{
343	    errVal = pMsg->fast;
344	    errOffset = 11;
345	}
346
347	if (errOffset >= 0)
348	{
349	    _IceErrorBadValue (iceConn, _SmcOpcode,
350	        SM_SaveYourself, errOffset, 1, (IcePointer) &errVal);
351	}
352	else
353	{
354	    (*smcConn->callbacks.save_yourself.callback) (smcConn,
355	        smcConn->callbacks.save_yourself.client_data,
356                pMsg->saveType, pMsg->shutdown,
357		pMsg->interactStyle, pMsg->fast);
358
359	    smcConn->save_yourself_in_progress = True;
360
361	    if (pMsg->shutdown)
362		smcConn->shutdown_in_progress = True;
363	}
364	break;
365    }
366
367    case SM_SaveYourselfPhase2:
368
369	if (!smcConn->phase2_wait)
370	{
371	    _IceErrorBadState (iceConn, _SmcOpcode,
372		SM_SaveYourselfPhase2, IceCanContinue);
373	}
374        else
375	{
376	    CHECK_SIZE_MATCH (iceConn, _SmcOpcode, opcode,
377	        length, SIZEOF (smSaveYourselfPhase2Msg),
378	        IceFatalToProtocol);
379
380	    (*smcConn->phase2_wait->phase2_proc) (smcConn,
381		smcConn->phase2_wait->client_data);
382
383	    free (smcConn->phase2_wait);
384	    smcConn->phase2_wait  = NULL;
385	}
386	break;
387
388    case SM_Interact:
389
390        if (!smcConn->interact_waits)
391	{
392	    _IceErrorBadState (iceConn, _SmcOpcode,
393		SM_Interact, IceCanContinue);
394	}
395        else
396	{
397	    _SmcInteractWait *next = smcConn->interact_waits->next;
398
399	    CHECK_SIZE_MATCH (iceConn, _SmcOpcode, opcode,
400	        length, SIZEOF (smInteractMsg),
401	        IceFatalToProtocol);
402
403	    (*smcConn->interact_waits->interact_proc) (smcConn,
404		smcConn->interact_waits->client_data);
405
406	    free (smcConn->interact_waits);
407	    smcConn->interact_waits = next;
408	}
409	break;
410
411    case SM_SaveComplete:
412
413	if (!smcConn->save_yourself_in_progress)
414	{
415	    _IceErrorBadState (iceConn, _SmcOpcode,
416		SM_SaveComplete, IceCanContinue);
417	}
418	else
419	{
420	    CHECK_SIZE_MATCH (iceConn, _SmcOpcode, opcode,
421	        length, SIZEOF (smSaveCompleteMsg),
422	        IceFatalToProtocol);
423
424	    smcConn->save_yourself_in_progress = False;
425
426	    (*smcConn->callbacks.save_complete.callback) (smcConn,
427	        smcConn->callbacks.save_complete.client_data);
428	}
429	break;
430
431    case SM_Die:
432
433	CHECK_SIZE_MATCH (iceConn, _SmcOpcode, opcode,
434	    length, SIZEOF (smDieMsg),
435	    IceFatalToProtocol);
436
437	(*smcConn->callbacks.die.callback) (smcConn,
438	    smcConn->callbacks.die.client_data);
439	break;
440
441    case SM_ShutdownCancelled:
442
443	if (!smcConn->shutdown_in_progress)
444	{
445	    _IceErrorBadState (iceConn, _SmcOpcode,
446		SM_ShutdownCancelled, IceCanContinue);
447	}
448	else
449	{
450	    CHECK_SIZE_MATCH (iceConn, _SmcOpcode, opcode,
451	        length, SIZEOF (smShutdownCancelledMsg),
452	        IceFatalToProtocol);
453
454	    smcConn->shutdown_in_progress = False;
455
456	    (*smcConn->callbacks.shutdown_cancelled.callback) (smcConn,
457	        smcConn->callbacks.shutdown_cancelled.client_data);
458	}
459	break;
460
461    case SM_PropertiesReply:
462
463        if (!smcConn->prop_reply_waits)
464	{
465	    _IceReadSkip (iceConn, length << 3);
466
467	    _IceErrorBadState (iceConn, _SmcOpcode,
468		SM_PropertiesReply, IceCanContinue);
469	}
470        else
471	{
472	    smPropertiesReplyMsg 	*pMsg;
473	    char 			*pStart, *pEnd;
474	    int				numProps = 0;
475	    SmProp			**props = NULL;
476	    _SmcPropReplyWait 		*next;
477
478	    CHECK_AT_LEAST_SIZE (iceConn, _SmcOpcode, opcode,
479		length, SIZEOF (smPropertiesReplyMsg), IceFatalToProtocol);
480
481	    IceReadCompleteMessage (iceConn, SIZEOF (smPropertiesReplyMsg),
482		smPropertiesReplyMsg, pMsg, pStart);
483
484	    if (!IceValidIO (iceConn) || pStart == NULL)
485	    {
486		IceDisposeCompleteMessage (iceConn, pStart);
487		return;
488	    }
489
490	    pEnd = pStart + (length << 3) -
491		(SIZEOF (smPropertiesReplyMsg) - SIZEOF (iceMsg));
492
493	    props = extractListofProperty(pStart, pEnd, swap, &numProps);
494	    if (props == NULL)
495	    {
496		_IceErrorBadLength (iceConn, _SmcOpcode, opcode,
497		    IceFatalToProtocol);
498		IceDisposeCompleteMessage (iceConn, pStart);
499		return;
500	    }
501
502	    next = smcConn->prop_reply_waits->next;
503
504	    (*smcConn->prop_reply_waits->prop_reply_proc) (smcConn,
505		smcConn->prop_reply_waits->client_data, numProps, props);
506
507	    free (smcConn->prop_reply_waits);
508	    smcConn->prop_reply_waits = next;
509
510	    IceDisposeCompleteMessage (iceConn, pStart);
511	}
512	break;
513
514    default:
515    {
516	_IceErrorBadMinor (iceConn, _SmcOpcode, opcode, IceCanContinue);
517	_IceReadSkip (iceConn, length << 3);
518	break;
519    }
520    }
521}
522
523
524
525void
526_SmsProcessMessage(IceConn iceConn, IcePointer clientData, int opcode,
527		   unsigned long length, Bool swap)
528{
529    SmsConn	smsConn = (SmsConn) clientData;
530
531    if (!smsConn->client_id &&
532        opcode != SM_RegisterClient && opcode != SM_Error)
533    {
534	_IceReadSkip (iceConn, length << 3);
535
536	_IceErrorBadState (iceConn, _SmsOpcode, opcode, IceFatalToProtocol);
537
538	return;
539    }
540
541    switch (opcode)
542    {
543    case SM_Error:
544    {
545	iceErrorMsg 	*pMsg;
546	char	    	*pData, *pEnd;
547
548	CHECK_AT_LEAST_SIZE (iceConn, _SmsOpcode, opcode,
549	    length, SIZEOF (iceErrorMsg), IceFatalToProtocol);
550
551	IceReadCompleteMessage (iceConn, SIZEOF (iceErrorMsg),
552	    iceErrorMsg, pMsg, pData);
553
554	if (!IceValidIO (iceConn) || pData == NULL)
555	{
556	    IceDisposeCompleteMessage (iceConn, pData);
557	    return;
558	}
559
560	if (swap)
561	{
562	    pMsg->errorClass = lswaps (pMsg->errorClass);
563	    pMsg->offendingSequenceNum = lswapl (pMsg->offendingSequenceNum);
564	}
565
566	pEnd = pData + (length << 3) - (SIZEOF (iceErrorMsg) - SIZEOF (iceMsg));
567
568	if (!validErrorMessage(pData, pEnd, pMsg->errorClass, swap))
569	{
570	    _IceErrorBadLength (iceConn, _SmcOpcode, opcode,
571		IceFatalToProtocol);
572	    IceDisposeCompleteMessage (iceConn, pData);
573	    return;
574	}
575
576	(*_SmsErrorHandler) (smsConn, swap,
577	    pMsg->offendingMinorOpcode,
578	    pMsg->offendingSequenceNum,
579	    pMsg->errorClass, pMsg->severity,
580            (SmPointer) pData);
581
582	IceDisposeCompleteMessage (iceConn, pData);
583	break;
584    }
585
586    case SM_RegisterClient:
587    {
588	smRegisterClientMsg 	*pMsg;
589	char 			*pData, *pStart, *pEnd;
590	char 			*previousId;
591	int                      idLen;
592
593	CHECK_AT_LEAST_SIZE (iceConn, _SmsOpcode, opcode,
594	    length, SIZEOF (smRegisterClientMsg), IceFatalToProtocol);
595
596	IceReadCompleteMessage (iceConn, SIZEOF (smRegisterClientMsg),
597	    smRegisterClientMsg, pMsg, pStart);
598
599	if (!IceValidIO (iceConn) || pStart == NULL)
600	{
601	    IceDisposeCompleteMessage (iceConn, pStart);
602	    return;
603	}
604
605	pData = pStart;
606	pEnd = pStart + (length << 3) -
607	    (SIZEOF (smRegisterClientMsg) - SIZEOF (iceMsg));
608
609	previousId = extractArray8(&pData, pEnd, swap, &idLen);
610	if (previousId == NULL)
611	{
612	    _IceErrorBadLength (iceConn, _SmcOpcode, opcode,
613		IceFatalToProtocol);
614	    IceDisposeCompleteMessage (iceConn, pStart);
615	    return;
616	}
617
618	if (*previousId == '\0')
619	{
620	    free (previousId);
621	    previousId = NULL;
622	}
623
624	if (!(*smsConn->callbacks.register_client.callback) (smsConn,
625            smsConn->callbacks.register_client.manager_data, previousId))
626	{
627	    /*
628	     * The previoudId was bad.  Generate BadValue error.
629	     */
630
631	    _IceErrorBadValue (smsConn->iceConn, _SmsOpcode, SM_RegisterClient,
632		8, ARRAY8_BYTES (idLen), (IcePointer) pStart);
633	}
634
635	IceDisposeCompleteMessage (iceConn, pStart);
636	break;
637    }
638
639    case SM_InteractRequest:
640
641        if (!smsConn->save_yourself_in_progress ||
642	    smsConn->interaction_allowed == SmInteractStyleNone)
643	{
644	    _IceErrorBadState (iceConn, _SmsOpcode,
645		SM_InteractRequest, IceCanContinue);
646	}
647        else
648	{
649	    smInteractRequestMsg 	*pMsg;
650
651	    CHECK_SIZE_MATCH (iceConn, _SmsOpcode, opcode,
652	        length, SIZEOF (smInteractRequestMsg),
653	        IceFatalToProtocol);
654
655	    IceReadSimpleMessage (iceConn, smInteractRequestMsg, pMsg);
656
657	    if (pMsg->dialogType != SmDialogNormal &&
658		pMsg->dialogType != SmDialogError)
659	    {
660		unsigned char errVal = pMsg->dialogType;
661
662		_IceErrorBadValue (iceConn, _SmsOpcode,
663	            SM_InteractRequest, 2, 1, (IcePointer) &errVal);
664	    }
665	    else if (pMsg->dialogType == SmDialogNormal &&
666		smsConn->interaction_allowed != SmInteractStyleAny)
667	    {
668		_IceErrorBadState (iceConn, _SmsOpcode,
669		    SM_InteractRequest, IceCanContinue);
670	    }
671	    else
672	    {
673		(*smsConn->callbacks.interact_request.callback) (smsConn,
674	            smsConn->callbacks.interact_request.manager_data,
675		    pMsg->dialogType);
676	    }
677	}
678	break;
679
680    case SM_InteractDone:
681
682        if (!smsConn->interact_in_progress)
683	{
684	    _IceErrorBadState (iceConn, _SmsOpcode,
685		SM_InteractDone, IceCanContinue);
686	}
687        else
688	{
689	    smInteractDoneMsg 	*pMsg;
690
691	    CHECK_SIZE_MATCH (iceConn, _SmsOpcode, opcode,
692	        length, SIZEOF (smInteractDoneMsg),
693	        IceFatalToProtocol);
694
695	    IceReadSimpleMessage (iceConn, smInteractDoneMsg, pMsg);
696
697	    if (pMsg->cancelShutdown != 1 &&
698		pMsg->cancelShutdown != 0)
699	    {
700		unsigned char errVal = pMsg->cancelShutdown;
701
702		_IceErrorBadValue (iceConn, _SmsOpcode,
703	            SM_InteractDone, 2, 1, (IcePointer) &errVal);
704	    }
705	    else if (pMsg->cancelShutdown && !smsConn->can_cancel_shutdown)
706	    {
707		_IceErrorBadState (iceConn, _SmsOpcode,
708		    SM_InteractDone, IceCanContinue);
709	    }
710	    else
711	    {
712		smsConn->interact_in_progress = False;
713
714		(*smsConn->callbacks.interact_done.callback) (smsConn,
715	            smsConn->callbacks.interact_done.manager_data,
716	            pMsg->cancelShutdown);
717	    }
718	}
719	break;
720
721    case SM_SaveYourselfRequest:
722    {
723	smSaveYourselfRequestMsg 	*pMsg;
724	unsigned char			errVal;
725	int				errOffset = -1;
726
727	CHECK_SIZE_MATCH (iceConn, _SmsOpcode, opcode,
728	    length, SIZEOF (smSaveYourselfRequestMsg),
729	    IceFatalToProtocol);
730
731	IceReadMessageHeader (iceConn, SIZEOF (smSaveYourselfRequestMsg),
732	    smSaveYourselfRequestMsg, pMsg);
733
734	if (!IceValidIO (iceConn))
735	{
736	    IceDisposeCompleteMessage (iceConn, pMsg);
737	    return;
738	}
739
740	if (pMsg->saveType != SmSaveGlobal &&
741	    pMsg->saveType != SmSaveLocal &&
742	    pMsg->saveType != SmSaveBoth)
743	{
744	    errVal = pMsg->saveType;
745	    errOffset = 8;
746	}
747	else if (pMsg->shutdown != 1 && pMsg->shutdown != 0)
748	{
749	    errVal = pMsg->shutdown;
750	    errOffset = 9;
751	}
752	else if (pMsg->interactStyle != SmInteractStyleNone &&
753	    pMsg->interactStyle != SmInteractStyleErrors &&
754	    pMsg->interactStyle != SmInteractStyleAny)
755	{
756	    errVal = pMsg->interactStyle;
757	    errOffset = 10;
758	}
759	else if (pMsg->fast != 1 && pMsg->fast != 0)
760	{
761	    errVal = pMsg->fast;
762	    errOffset = 11;
763	}
764	else if (pMsg->global != 1 && pMsg->global != 0)
765	{
766	    errVal = pMsg->fast;
767	    errOffset = 11;
768	}
769
770	if (errOffset >= 0)
771	{
772	    _IceErrorBadValue (iceConn, _SmsOpcode,
773	        SM_SaveYourselfRequest, errOffset, 1, (IcePointer) &errVal);
774	}
775	else
776	{
777	    (*smsConn->callbacks.save_yourself_request.callback) (smsConn,
778	        smsConn->callbacks.save_yourself_request.manager_data,
779                pMsg->saveType, pMsg->shutdown, pMsg->interactStyle,
780	        pMsg->fast, pMsg->global);
781	}
782	break;
783    }
784
785    case SM_SaveYourselfPhase2Request:
786
787        if (!smsConn->save_yourself_in_progress)
788	{
789	    _IceErrorBadState (iceConn, _SmsOpcode,
790		SM_SaveYourselfPhase2Request, IceCanContinue);
791	}
792        else
793	{
794	    CHECK_SIZE_MATCH (iceConn, _SmsOpcode, opcode,
795	        length, SIZEOF (smSaveYourselfPhase2RequestMsg),
796	        IceFatalToProtocol);
797
798	    (*smsConn->callbacks.save_yourself_phase2_request.callback) (
799		smsConn, smsConn->callbacks.
800		save_yourself_phase2_request.manager_data);
801	}
802	break;
803
804    case SM_SaveYourselfDone:
805
806        if (!smsConn->save_yourself_in_progress)
807	{
808	    _IceErrorBadState (iceConn, _SmsOpcode,
809		SM_SaveYourselfDone, IceCanContinue);
810	}
811        else
812	{
813	    smSaveYourselfDoneMsg 	*pMsg;
814
815	    CHECK_SIZE_MATCH (iceConn, _SmsOpcode, opcode,
816	        length, SIZEOF (smSaveYourselfDoneMsg),
817	        IceFatalToProtocol);
818
819	    IceReadSimpleMessage (iceConn, smSaveYourselfDoneMsg, pMsg);
820
821	    if (pMsg->success != 1 && pMsg->success != 0)
822	    {
823		unsigned char errVal = pMsg->success;
824
825		_IceErrorBadValue (iceConn, _SmsOpcode,
826	            SM_SaveYourselfDone, 2, 1, (IcePointer) &errVal);
827	    }
828	    else
829	    {
830		smsConn->save_yourself_in_progress = False;
831		smsConn->interaction_allowed = SmInteractStyleNone;
832
833		(*smsConn->callbacks.save_yourself_done.callback) (smsConn,
834	            smsConn->callbacks.save_yourself_done.manager_data,
835		    pMsg->success);
836	    }
837	}
838	break;
839
840    case SM_CloseConnection:
841    {
842	smCloseConnectionMsg 	*pMsg;
843	char 			*pData, *pStart, *pEnd;
844	int 			count, i;
845	char 			**reasonMsgs = NULL;
846
847	CHECK_AT_LEAST_SIZE (iceConn, _SmsOpcode, opcode,
848	    length, SIZEOF (smCloseConnectionMsg) + 8, IceFatalToProtocol);
849
850	IceReadCompleteMessage (iceConn, SIZEOF (smCloseConnectionMsg),
851	    smCloseConnectionMsg, pMsg, pStart);
852
853	if (!IceValidIO (iceConn) || pStart == NULL)
854	{
855	    IceDisposeCompleteMessage (iceConn, pStart);
856	    return;
857	}
858
859	pData = pStart;
860	pEnd = pStart + (length << 3) -
861	    (SIZEOF (smCloseConnectionMsg) - SIZEOF (iceMsg));
862
863	EXTRACT_CARD32 (pData, swap, count);
864	pData += 4;
865
866	if (count < 0 || count > INT_MAX / sizeof (char *) ||
867	    (reasonMsgs = malloc (count * sizeof (char *))) == NULL)
868	{
869	    _IceErrorBadLength (iceConn, _SmcOpcode, opcode, IceFatalToProtocol);
870	    IceDisposeCompleteMessage (iceConn, pStart);
871	    return;
872	}
873
874	for (i = 0; i < count; i++)
875	{
876	    reasonMsgs[i] = extractArray8(&pData, pEnd, swap, NULL);
877	    if (reasonMsgs[i] == NULL)
878		break;
879	}
880	if (i != count) {
881	    while (i-- > 0)
882		free (reasonMsgs[i]);
883	    free (reasonMsgs);
884	    _IceErrorBadLength (iceConn, _SmcOpcode, opcode,
885		IceFatalToProtocol);
886	    IceDisposeCompleteMessage (iceConn, pStart);
887	    return;
888	}
889
890	IceDisposeCompleteMessage (iceConn, pStart);
891
892	(*smsConn->callbacks.close_connection.callback) (smsConn,
893	    smsConn->callbacks.close_connection.manager_data,
894	    count, reasonMsgs);
895	break;
896    }
897
898    case SM_SetProperties:
899    {
900	smSetPropertiesMsg 	*pMsg;
901	char 			*pStart, *pEnd;
902	SmProp			**props = NULL;
903	int 			numProps = 0;
904
905	CHECK_AT_LEAST_SIZE (iceConn, _SmsOpcode, opcode,
906	    length, SIZEOF (smSetPropertiesMsg), IceFatalToProtocol);
907
908	IceReadCompleteMessage (iceConn, SIZEOF (smSetPropertiesMsg),
909	    smSetPropertiesMsg, pMsg, pStart);
910
911	if (!IceValidIO (iceConn) || pStart == NULL)
912	{
913	    IceDisposeCompleteMessage (iceConn, pStart);
914	    return;
915	}
916
917	pEnd = pStart + (length << 3) -
918	    (SIZEOF (smSetPropertiesMsg) - SIZEOF (iceMsg));
919
920	props = extractListofProperty(pStart, pEnd, swap, &numProps);
921	if (props == NULL)
922	{
923	    _IceErrorBadLength (iceConn, _SmcOpcode, opcode,
924		IceFatalToProtocol);
925	    IceDisposeCompleteMessage (iceConn, pStart);
926	    return;
927	}
928
929	(*smsConn->callbacks.set_properties.callback) (smsConn,
930	    smsConn->callbacks.set_properties.manager_data, numProps, props);
931
932	IceDisposeCompleteMessage (iceConn, pStart);
933	break;
934    }
935
936    case SM_DeleteProperties:
937    {
938	smDeletePropertiesMsg 	*pMsg;
939	char 			*pData, *pStart, *pEnd;
940	int 			count, i;
941	char 			**propNames = NULL;
942
943	CHECK_AT_LEAST_SIZE (iceConn, _SmsOpcode, opcode,
944	    length, SIZEOF (smDeletePropertiesMsg) + 8, IceFatalToProtocol);
945
946	IceReadCompleteMessage (iceConn, SIZEOF (smDeletePropertiesMsg),
947	    smDeletePropertiesMsg, pMsg, pStart);
948
949	if (!IceValidIO (iceConn) || pStart == NULL)
950	{
951	    IceDisposeCompleteMessage (iceConn, pStart);
952	    return;
953	}
954
955	pData = pStart;
956	pEnd = pStart + (length << 3) -
957	    (SIZEOF (smDeletePropertiesMsg) - SIZEOF (iceMsg));
958
959	EXTRACT_CARD32 (pData, swap, count);
960	pData += 4;
961
962	if (count < 0 || count > INT_MAX / sizeof (char *) ||
963	    (propNames = malloc (count * sizeof (char *))) == NULL)
964	{
965	    IceDisposeCompleteMessage (iceConn, pStart);
966	    return;
967	}
968
969	for (i = 0; i < count; i++)
970	{
971	    propNames[i] = extractArray8(&pData, pEnd, swap, NULL);
972	    if (propNames[i] == NULL)
973		break;
974	}
975	if (i != count)
976	{
977	    while (i-- > 0)
978		free (propNames[i]);
979	    free (propNames);
980	    _IceErrorBadLength (iceConn, _SmcOpcode, opcode,
981		IceFatalToProtocol);
982	    IceDisposeCompleteMessage (iceConn, pStart);
983	    return;
984	}
985
986	IceDisposeCompleteMessage (iceConn, pStart);
987
988	(*smsConn->callbacks.delete_properties.callback) (smsConn,
989	    smsConn->callbacks.delete_properties.manager_data,
990	    count, propNames);
991
992	break;
993    }
994
995    case SM_GetProperties:
996
997	CHECK_SIZE_MATCH (iceConn, _SmsOpcode, opcode,
998	    length, SIZEOF (smGetPropertiesMsg),
999	    IceFatalToProtocol);
1000
1001	(*smsConn->callbacks.get_properties.callback) (smsConn,
1002	    smsConn->callbacks.get_properties.manager_data);
1003	break;
1004
1005    default:
1006    {
1007	_IceErrorBadMinor (iceConn, _SmsOpcode, opcode, IceCanContinue);
1008	_IceReadSkip (iceConn, length << 3);
1009	break;
1010    }
1011    }
1012}
1013