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 "SMlibint.h"
36 
37 int 	_SmcOpcode = 0;
38 int 	_SmsOpcode = 0;
39 
40 SmsNewClientProc _SmsNewClientProc;
41 SmPointer        _SmsNewClientData;
42 
43 SmcErrorHandler _SmcErrorHandler = _SmcDefaultErrorHandler;
44 SmsErrorHandler _SmsErrorHandler = _SmsDefaultErrorHandler;
45 
46 
47 static void
48 set_callbacks(SmcConn smcConn, unsigned long mask, SmcCallbacks *callbacks);
49 
50 
51 SmcConn
SmcOpenConnection(char * networkIdsList,SmPointer context,int xsmpMajorRev,int xsmpMinorRev,unsigned long mask,SmcCallbacks * callbacks,const char * previousId,char ** clientIdRet,int errorLength,char * errorStringRet)52 SmcOpenConnection(char *networkIdsList, SmPointer context,
53 		  int xsmpMajorRev, int xsmpMinorRev,
54 		  unsigned long mask, SmcCallbacks *callbacks,
55 		  const char *previousId, char **clientIdRet,
56 		  int errorLength, char *errorStringRet)
57 {
58     SmcConn			smcConn;
59     IceConn			iceConn;
60     char 			*ids;
61     IceProtocolSetupStatus	setupstat;
62     int				majorVersion;
63     int				minorVersion;
64     char			*vendor = NULL;
65     char			*release = NULL;
66     smRegisterClientMsg 	*pMsg;
67     char 			*pData;
68     unsigned int		extra, len;
69     IceReplyWaitInfo		replyWait;
70     _SmcRegisterClientReply	reply;
71     Bool			gotReply, ioErrorOccured;
72 
73     const char *auth_names[] = {"MIT-MAGIC-COOKIE-1"};
74     IcePoAuthProc auth_procs[] = {_IcePoMagicCookie1Proc};
75     int auth_count = 1;
76 
77     IcePoVersionRec versions[] = {
78         {SmProtoMajor, SmProtoMinor, _SmcProcessMessage}
79     };
80     int version_count = 1;
81 
82 
83     *clientIdRet = NULL;
84 
85     if (errorStringRet && errorLength > 0)
86 	*errorStringRet = '\0';
87 
88     if (!_SmcOpcode)
89     {
90 	/*
91 	 * For now, there is only one version of XSMP, so we don't
92 	 * have to check {xsmpMajorRev, xsmpMinorRev}.  In the future,
93 	 * we will check against versions and generate the list
94 	 * of versions the application actually supports.
95 	 */
96 
97 	if ((_SmcOpcode = IceRegisterForProtocolSetup ("XSMP",
98 	    SmVendorString, SmReleaseString, version_count, versions,
99             auth_count, auth_names, auth_procs, NULL)) < 0)
100 	{
101 	    if (errorStringRet && errorLength > 0) {
102 		strncpy (errorStringRet,
103 			 "Could not register XSMP protocol with ICE",
104 			 errorLength);
105 		errorStringRet[errorLength - 1] = '\0';
106 	    }
107 
108 	    return (NULL);
109 	}
110     }
111 
112     if (networkIdsList == NULL || *networkIdsList == '\0')
113     {
114 	if ((ids = (char *) getenv ("SESSION_MANAGER")) == NULL)
115 	{
116 	    if (errorStringRet && errorLength > 0) {
117 		strncpy (errorStringRet,
118 			 "SESSION_MANAGER environment variable not defined",
119 			 errorLength);
120 		errorStringRet[errorLength - 1] = '\0';
121 	    }
122 	    return (NULL);
123 	}
124     }
125     else
126     {
127 	ids = networkIdsList;
128     }
129 
130     if ((iceConn = IceOpenConnection (
131 	ids, context, 0, _SmcOpcode, errorLength, errorStringRet)) == NULL)
132     {
133 	return (NULL);
134     }
135 
136     if ((smcConn = malloc (sizeof (struct _SmcConn))) == NULL)
137     {
138 	if (errorStringRet && errorLength > 0) {
139 	    strncpy (errorStringRet, "Can't malloc", errorLength);
140 	    errorStringRet[errorLength - 1] = '\0';
141 	}
142 	IceCloseConnection (iceConn);
143 	return (NULL);
144     }
145 
146     setupstat = IceProtocolSetup (iceConn, _SmcOpcode,
147 	(IcePointer) smcConn,
148 	False /* mustAuthenticate */,
149 	&majorVersion, &minorVersion,
150 	&vendor, &release, errorLength, errorStringRet);
151 
152     if (setupstat == IceProtocolSetupFailure ||
153 	setupstat == IceProtocolSetupIOError)
154     {
155 	IceCloseConnection (iceConn);
156 	free (smcConn);
157 	return (NULL);
158     }
159     else if (setupstat == IceProtocolAlreadyActive)
160     {
161 	/*
162 	 * This case should never happen, because when we called
163 	 * IceOpenConnection, we required that the ICE connection
164 	 * may not already have XSMP active on it.
165 	 */
166 
167 	free (smcConn);
168 	if (errorStringRet && errorLength > 0) {
169 	    strncpy (errorStringRet, "Internal error in IceOpenConnection",
170 		     errorLength);
171 	    errorStringRet[errorLength - 1] = '\0';
172 	}
173 	return (NULL);
174     }
175 
176     smcConn->iceConn = iceConn;
177     smcConn->proto_major_version = majorVersion;
178     smcConn->proto_minor_version = minorVersion;
179     smcConn->vendor = vendor;
180     smcConn->release = release;
181     smcConn->client_id = NULL;
182 
183     bzero ((char *) &smcConn->callbacks, sizeof (SmcCallbacks));
184     set_callbacks (smcConn, mask, callbacks);
185 
186     smcConn->interact_waits = NULL;
187     smcConn->phase2_wait = NULL;
188     smcConn->prop_reply_waits = NULL;
189 
190     smcConn->save_yourself_in_progress = False;
191     smcConn->shutdown_in_progress = False;
192 
193 
194     /*
195      * Now register the client
196      */
197 
198     if (!previousId)
199 	previousId = "";
200     len = strlen (previousId);
201     extra = ARRAY8_BYTES (len);
202 
203     IceGetHeaderExtra (iceConn, _SmcOpcode, SM_RegisterClient,
204 	SIZEOF (smRegisterClientMsg), WORD64COUNT (extra),
205 	smRegisterClientMsg, pMsg, pData);
206 
207     STORE_ARRAY8 (pData, len, previousId);
208 
209     IceFlush (iceConn);
210 
211     replyWait.sequence_of_request = IceLastSentSequenceNumber (iceConn);
212     replyWait.major_opcode_of_request = _SmcOpcode;
213     replyWait.minor_opcode_of_request = SM_RegisterClient;
214     replyWait.reply = (IcePointer) &reply;
215 
216     gotReply = False;
217     ioErrorOccured = False;
218 
219     while (!gotReply && !ioErrorOccured)
220     {
221 	ioErrorOccured = (IceProcessMessages (
222 	    iceConn, &replyWait, &gotReply) == IceProcessMessagesIOError);
223 
224 	if (ioErrorOccured)
225 	{
226 	    if (errorStringRet && errorLength > 0) {
227 		strncpy (errorStringRet, "IO error occured opening connection",
228 			 errorLength);
229 		errorStringRet[errorLength - 1] = '\0';
230 	    }
231 	    free (smcConn->vendor);
232 	    free (smcConn->release);
233 	    free (smcConn);
234 
235 	    return (NULL);
236 	}
237 	else if (gotReply)
238 	{
239 	    if (reply.status == 1)
240 	    {
241 		/*
242 		 * The client successfully registered.
243 		 */
244 
245 		*clientIdRet = reply.client_id;
246 
247 		smcConn->client_id = strdup (*clientIdRet);
248 	    }
249 	    else
250 	    {
251 		/*
252 		 * Could not register the client because the previous ID
253 		 * was bad.  So now we register the client with the
254 		 * previous ID set to NULL.
255 		 */
256 
257 		extra = ARRAY8_BYTES (0);
258 
259 		IceGetHeaderExtra (iceConn, _SmcOpcode, SM_RegisterClient,
260 		    SIZEOF (smRegisterClientMsg), WORD64COUNT (extra),
261 		    smRegisterClientMsg, pMsg, pData);
262 
263 		STORE_ARRAY8 (pData, 0, "");
264 
265 		IceFlush (iceConn);
266 
267 		replyWait.sequence_of_request =
268 		    IceLastSentSequenceNumber (iceConn);
269 
270 		gotReply = False;
271 	    }
272 	}
273     }
274 
275     return (smcConn);
276 }
277 
278 
279 
280 SmcCloseStatus
SmcCloseConnection(SmcConn smcConn,int count,char ** reasonMsgs)281 SmcCloseConnection(SmcConn smcConn, int count, char **reasonMsgs)
282 {
283     IceConn			iceConn = smcConn->iceConn;
284     smCloseConnectionMsg 	*pMsg;
285     char 			*pData;
286     int				extra, i;
287     IceCloseStatus	        closeStatus;
288     SmcCloseStatus		statusRet;
289 
290     extra = 8;
291 
292     for (i = 0; i < count; i++)
293 	extra += ARRAY8_BYTES (strlen (reasonMsgs[i]));
294 
295     IceGetHeaderExtra (iceConn, _SmcOpcode, SM_CloseConnection,
296 	SIZEOF (smCloseConnectionMsg), WORD64COUNT (extra),
297 	smCloseConnectionMsg, pMsg, pData);
298 
299     STORE_CARD32 (pData, (CARD32) count);
300     pData += 4;
301 
302     for (i = 0; i < count; i++)
303 	STORE_ARRAY8 (pData, strlen (reasonMsgs[i]), reasonMsgs[i]);
304 
305     IceFlush (iceConn);
306 
307     IceProtocolShutdown (iceConn, _SmcOpcode);
308     IceSetShutdownNegotiation (iceConn, False);
309     closeStatus = IceCloseConnection (iceConn);
310 
311     if (smcConn->vendor)
312 	free (smcConn->vendor);
313 
314     if (smcConn->release)
315 	free (smcConn->release);
316 
317     if (smcConn->client_id)
318 	free (smcConn->client_id);
319 
320     if (smcConn->prop_reply_waits)
321     {
322 	_SmcPropReplyWait *ptr = smcConn->prop_reply_waits;
323 	_SmcPropReplyWait *next;
324 
325 	while (ptr)
326 	{
327 	    next = ptr->next;
328 	    free (ptr);
329 	    ptr = next;
330 	}
331 
332     }
333 
334     free (smcConn);
335 
336     if (closeStatus == IceClosedNow)
337 	statusRet = SmcClosedNow;
338     else if (closeStatus == IceClosedASAP)
339 	statusRet = SmcClosedASAP;
340     else
341 	statusRet = SmcConnectionInUse;
342 
343     return (statusRet);
344 }
345 
346 
347 
348 void
SmcModifyCallbacks(SmcConn smcConn,unsigned long mask,SmcCallbacks * callbacks)349 SmcModifyCallbacks(SmcConn smcConn, unsigned long mask, SmcCallbacks *callbacks)
350 {
351     set_callbacks (smcConn, mask, callbacks);
352 }
353 
354 
355 
356 void
SmcSetProperties(SmcConn smcConn,int numProps,SmProp ** props)357 SmcSetProperties(SmcConn smcConn, int numProps, SmProp **props)
358 {
359     IceConn		iceConn = smcConn->iceConn;
360     smSetPropertiesMsg	*pMsg;
361     char		*pBuf;
362     char		*pStart;
363     unsigned int	bytes;
364 
365     IceGetHeader (iceConn, _SmcOpcode, SM_SetProperties,
366 	SIZEOF (smSetPropertiesMsg), smSetPropertiesMsg, pMsg);
367 
368     LISTOF_PROP_BYTES (numProps, props, bytes);
369     pMsg->length += WORD64COUNT (bytes);
370 
371     pBuf = pStart = IceAllocScratch (iceConn, bytes);
372     memset(pStart, 0, bytes);
373 
374     STORE_LISTOF_PROPERTY (pBuf, numProps, props);
375 
376     IceWriteData (iceConn, bytes, pStart);
377     IceFlush (iceConn);
378 }
379 
380 
381 
382 void
SmcDeleteProperties(SmcConn smcConn,int numProps,char ** propNames)383 SmcDeleteProperties(SmcConn smcConn, int numProps, char **propNames)
384 {
385     IceConn			iceConn = smcConn->iceConn;
386     smDeletePropertiesMsg 	*pMsg;
387     char 			*pData;
388     int				extra, i;
389 
390     extra = 8;
391 
392     for (i = 0; i < numProps; i++)
393 	extra += ARRAY8_BYTES (strlen (propNames[i]));
394 
395     IceGetHeaderExtra (iceConn, _SmcOpcode, SM_DeleteProperties,
396 	SIZEOF (smDeletePropertiesMsg), WORD64COUNT (extra),
397 	smDeletePropertiesMsg, pMsg, pData);
398 
399     STORE_CARD32 (pData, numProps);
400     pData += 4;
401 
402     for (i = 0; i < numProps; i++)
403 	STORE_ARRAY8 (pData, strlen (propNames[i]), propNames[i]);
404 
405     IceFlush (iceConn);
406 }
407 
408 
409 
410 Status
SmcGetProperties(SmcConn smcConn,SmcPropReplyProc propReplyProc,SmPointer clientData)411 SmcGetProperties(SmcConn smcConn, SmcPropReplyProc propReplyProc,
412 		 SmPointer clientData)
413 {
414     IceConn		iceConn = smcConn->iceConn;
415     _SmcPropReplyWait 	*wait, *ptr;
416 
417     if ((wait = malloc (sizeof (_SmcPropReplyWait))) == NULL)
418     {
419 	return (0);
420     }
421 
422     wait->prop_reply_proc = propReplyProc;
423     wait->client_data = clientData;
424     wait->next = NULL;
425 
426     ptr = smcConn->prop_reply_waits;
427     while (ptr && ptr->next)
428 	ptr = ptr->next;
429 
430     if (ptr == NULL)
431 	smcConn->prop_reply_waits = wait;
432     else
433 	ptr->next = wait;
434 
435     IceSimpleMessage (iceConn, _SmcOpcode, SM_GetProperties);
436     IceFlush (iceConn);
437 
438     return (1);
439 }
440 
441 
442 
443 Status
SmcInteractRequest(SmcConn smcConn,int dialogType,SmcInteractProc interactProc,SmPointer clientData)444 SmcInteractRequest(SmcConn smcConn, int dialogType,
445 		   SmcInteractProc interactProc, SmPointer clientData)
446 {
447     IceConn			iceConn = smcConn->iceConn;
448     smInteractRequestMsg	*pMsg;
449     _SmcInteractWait 		*wait, *ptr;
450 
451     if ((wait = malloc (sizeof (_SmcInteractWait))) == NULL)
452     {
453 	return (0);
454     }
455 
456     wait->interact_proc = interactProc;
457     wait->client_data = clientData;
458     wait->next = NULL;
459 
460     ptr = smcConn->interact_waits;
461     while (ptr && ptr->next)
462 	ptr = ptr->next;
463 
464     if (ptr == NULL)
465 	smcConn->interact_waits = wait;
466     else
467 	ptr->next = wait;
468 
469     IceGetHeader (iceConn, _SmcOpcode, SM_InteractRequest,
470 	SIZEOF (smInteractRequestMsg), smInteractRequestMsg, pMsg);
471 
472     pMsg->dialogType = dialogType;
473 
474     IceFlush (iceConn);
475 
476     return (1);
477 }
478 
479 
480 
481 void
SmcInteractDone(SmcConn smcConn,Bool cancelShutdown)482 SmcInteractDone(SmcConn smcConn, Bool cancelShutdown)
483 {
484     IceConn		iceConn = smcConn->iceConn;
485     smInteractDoneMsg	*pMsg;
486 
487     IceGetHeader (iceConn, _SmcOpcode, SM_InteractDone,
488 	SIZEOF (smInteractDoneMsg), smInteractDoneMsg, pMsg);
489 
490     pMsg->cancelShutdown = cancelShutdown;
491 
492     IceFlush (iceConn);
493 }
494 
495 
496 
497 void
SmcRequestSaveYourself(SmcConn smcConn,int saveType,Bool shutdown,int interactStyle,Bool fast,Bool global)498 SmcRequestSaveYourself(SmcConn smcConn, int saveType, Bool shutdown,
499 		       int interactStyle, Bool fast, Bool global)
500 {
501     IceConn			iceConn = smcConn->iceConn;
502     smSaveYourselfRequestMsg	*pMsg;
503 
504     IceGetHeader (iceConn, _SmcOpcode, SM_SaveYourselfRequest,
505 	SIZEOF (smSaveYourselfRequestMsg), smSaveYourselfRequestMsg, pMsg);
506 
507     pMsg->saveType = saveType;
508     pMsg->shutdown = shutdown;
509     pMsg->interactStyle = interactStyle;
510     pMsg->fast = fast;
511     pMsg->global = global;
512 
513     IceFlush (iceConn);
514 }
515 
516 
517 
518 Status
SmcRequestSaveYourselfPhase2(SmcConn smcConn,SmcSaveYourselfPhase2Proc saveYourselfPhase2Proc,SmPointer clientData)519 SmcRequestSaveYourselfPhase2(SmcConn smcConn,
520 			     SmcSaveYourselfPhase2Proc saveYourselfPhase2Proc,
521 			     SmPointer clientData)
522 {
523     IceConn		iceConn = smcConn->iceConn;
524     _SmcPhase2Wait 	*wait;
525 
526     if (smcConn->phase2_wait)
527 	wait = smcConn->phase2_wait;
528     else
529     {
530 	if ((wait = malloc (sizeof (_SmcPhase2Wait))) == NULL)
531 	{
532 	    return (0);
533 	}
534     }
535 
536     wait->phase2_proc = saveYourselfPhase2Proc;
537     wait->client_data = clientData;
538 
539     smcConn->phase2_wait = wait;
540 
541     IceSimpleMessage (iceConn, _SmcOpcode, SM_SaveYourselfPhase2Request);
542     IceFlush (iceConn);
543 
544     return (1);
545 }
546 
547 
548 
549 void
SmcSaveYourselfDone(SmcConn smcConn,Bool success)550 SmcSaveYourselfDone(SmcConn smcConn, Bool success)
551 {
552     IceConn			iceConn = smcConn->iceConn;
553     smSaveYourselfDoneMsg	*pMsg;
554 
555     IceGetHeader (iceConn, _SmcOpcode, SM_SaveYourselfDone,
556 	SIZEOF (smSaveYourselfDoneMsg), smSaveYourselfDoneMsg, pMsg);
557 
558     pMsg->success = success;
559 
560     IceFlush (iceConn);
561 }
562 
563 
564 
565 static void
set_callbacks(SmcConn smcConn,unsigned long mask,SmcCallbacks * callbacks)566 set_callbacks(SmcConn smcConn, unsigned long mask, SmcCallbacks *callbacks)
567 {
568     if (mask & SmcSaveYourselfProcMask)
569     {
570 	smcConn->callbacks.save_yourself.callback =
571 	    callbacks->save_yourself.callback;
572 	smcConn->callbacks.save_yourself.client_data =
573 	    callbacks->save_yourself.client_data;
574     }
575 
576     if (mask & SmcDieProcMask)
577     {
578 	smcConn->callbacks.die.callback = callbacks->die.callback;
579 	smcConn->callbacks.die.client_data = callbacks->die.client_data;
580     }
581 
582     if (mask & SmcSaveCompleteProcMask)
583     {
584 	smcConn->callbacks.save_complete.callback =
585 	    callbacks->save_complete.callback;
586 	smcConn->callbacks.save_complete.client_data =
587 	    callbacks->save_complete.client_data;
588     }
589 
590     if (mask & SmcShutdownCancelledProcMask)
591     {
592 	smcConn->callbacks.shutdown_cancelled.callback =
593 	    callbacks->shutdown_cancelled.callback;
594 	smcConn->callbacks.shutdown_cancelled.client_data =
595 	    callbacks->shutdown_cancelled.client_data;
596     }
597 }
598