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