1 /*
2 
3 Copyright 1993, 1998  The Open Group
4 
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10 
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
24 
25 */
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 
58 static char *
extractArray8(char ** pBuf,char * pEnd,Bool swap,int * len)59 extractArray8(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 
83 static SmProp **
extractListofProperty(char * pBuf,char * pEnd,Bool swap,int * count)84 extractListofProperty(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 
132 fail:
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 
153 static Bool
validErrorMessage(char * pData,char * pEnd,int errorClass,Bool swap)154 validErrorMessage(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 
173 void
_SmcProcessMessage(IceConn iceConn,IcePointer clientData,int opcode,unsigned long length,Bool swap,IceReplyWaitInfo * replyWait,Bool * replyReadyRet)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))
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))
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))
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 
525 void
_SmsProcessMessage(IceConn iceConn,IcePointer clientData,int opcode,unsigned long length,Bool swap)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))
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))
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))
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))
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))
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