Bug Summary

File:smproxy.c
Location:line 976, column 12
Description:Potential leak of memory pointed to by 'prop1.vals'

Annotated Source Code

1/******************************************************************************
2
3Copyright 1994, 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
25Author: Ralph Mor, X Consortium
26******************************************************************************/
27
28#include "smproxy.h"
29#include <unistd.h>
30#include <X11/Xmu/WinUtil.h>
31
32static XtAppContext appContext;
33static Display *disp;
34
35static Atom wmProtocolsAtom;
36static Atom wmSaveYourselfAtom;
37static Atom wmStateAtom;
38static Atom smClientIdAtom;
39static Atom wmClientLeaderAtom;
40
41static Boolint debug = 0;
42
43static SmcConn proxy_smcConn;
44static XtInputId proxy_iceInputId;
45static char *proxy_clientId = NULL((void*)0);
46
47WinInfo *win_head = NULL((void*)0);
48
49static int proxy_count = 0;
50static int die_count = 0;
51
52static Boolint ok_to_die = 0;
53
54static Boolint caught_error = 0;
55
56static Boolint sent_save_done = 0;
57
58static int Argc;
59static char **Argv;
60
61static Boolint HasSaveYourself ( Window window );
62static Boolint HasXSMPsupport ( Window window );
63static WinInfo * GetClientLeader ( WinInfo *winptr );
64static char * CheckFullyQuantifiedName ( char *name, int *newstring );
65static void FinishSaveYourself ( WinInfo *winInfo, Boolint has_WM_SAVEYOURSELF );
66static void SaveYourselfCB ( SmcConn smcConn, SmPointer clientData, int saveType,
67 Boolint shutdown, int interactStyle, Boolint fast );
68static void DieCB ( SmcConn smcConn, SmPointer clientData );
69static void SaveCompleteCB ( SmcConn smcConn, SmPointer clientData );
70static void ShutdownCancelledCB ( SmcConn smcConn, SmPointer clientData );
71static void ProcessIceMsgProc ( XtPointer client_data, int *source, XtInputId *id );
72static void NullIceErrorHandler ( IceConn iceConn, Boolint swap,
73 int offendingMinorOpCode,
74 unsigned long offendingSequence,
75 int errorClass, int severity, IcePointer values );
76static void ConnectClientToSM ( WinInfo *winInfo );
77static int MyErrorHandler ( Display *display, XErrorEvent *event );
78static Boolint LookupWindow ( Window window, WinInfo **ptr_ret, WinInfo **prev_ptr_ret );
79static WinInfo * AddNewWindow ( Window window );
80static void RemoveWindow ( WinInfo *winptr );
81static void Got_WM_STATE ( WinInfo *winptr );
82static void HandleCreate ( XCreateWindowEvent *event );
83static void HandleDestroy ( XDestroyWindowEvent *event );
84static void HandleUpdate ( XPropertyEvent *event );
85static void ProxySaveYourselfPhase2CB ( SmcConn smcConn, SmPointer clientData );
86static void ProxySaveYourselfCB ( SmcConn smcConn, SmPointer clientData,
87 int saveType, Boolint shutdown, int interactStyle,
88 Boolint fast );
89static void ProxyDieCB ( SmcConn smcConn, SmPointer clientData );
90static void ProxySaveCompleteCB ( SmcConn smcConn, SmPointer clientData );
91static void ProxyShutdownCancelledCB ( SmcConn smcConn, SmPointer clientData );
92static Statusint ConnectProxyToSM ( char *previous_id );
93static void CheckForExistingWindows ( Window root );
94
95
96static Boolint
97HasSaveYourself(Window window)
98{
99 Atom *protocols;
100 int numProtocols;
101 int i, found;
102
103 protocols = NULL((void*)0);
104
105 if (XGetWMProtocols (disp, window, &protocols, &numProtocols) != True1)
106 return (False0);
107
108 found = 0;
109
110 if (protocols != NULL((void*)0))
111 {
112 for (i = 0; i < numProtocols; i++)
113 if (protocols[i] == wmSaveYourselfAtom)
114 found = 1;
115
116 XFree (protocols);
117 }
118
119 return (found);
120}
121
122
123
124static Boolint
125HasXSMPsupport(Window window)
126{
127 XTextProperty tp;
128 Boolint hasIt = 0;
129
130 if (XGetTextProperty (disp, window, &tp, smClientIdAtom))
131 {
132 if (tp.encoding == XA_STRING((Atom) 31) && tp.format == 8 && tp.nitems != 0)
133 hasIt = 1;
134
135 if (tp.value)
136 XFree ((char *) tp.value);
137 }
138
139 return (hasIt);
140}
141
142
143
144static WinInfo *
145GetClientLeader(WinInfo *winptr)
146{
147 Atom actual_type;
148 int actual_format;
149 unsigned long nitems, bytesafter;
150 unsigned long *datap = NULL((void*)0);
151 WinInfo *leader_winptr = NULL((void*)0);
152 Boolint failure = 0;
153
154 if (XGetWindowProperty (disp, winptr->window, wmClientLeaderAtom,
155 0L, 1L, False0, AnyPropertyType0L, &actual_type, &actual_format,
156 &nitems, &bytesafter, (unsigned char **) &datap) == Success0)
157 {
158 if (actual_type == XA_WINDOW((Atom) 33) && actual_format == 32 &&
159 nitems == 1 && bytesafter == 0)
160 {
161 Window leader_win = *((Window *) datap);
162
163 if (!LookupWindow (leader_win, &leader_winptr, NULL((void*)0)))
164 failure = 1;
165 }
166
167 if (datap)
168 XFree (datap);
169 }
170
171 if (failure)
172 {
173 /* The client leader was defined, but we couldn't find the window */
174
175 return (NULL((void*)0));
176 }
177 else if (leader_winptr)
178 {
179 /* We found the real client leader */
180
181 return (leader_winptr);
182 }
183 else
184 {
185 /* There is no client leader defined, return this window */
186
187 return (winptr);
188 }
189}
190
191
192
193static char *
194CheckFullyQuantifiedName(char *name, int *newstring)
195{
196 /*
197 * Due to a bug in Xlib (for hpux in particular), some clients
198 * will have a WM_CLIENT_MACHINE that is not fully quantified.
199 * For example, we might get "excon" instead of "excon.x.org".
200 * This really stinks. The best we can do is tag on our own
201 * domain name.
202 */
203
204 if (strchr (name, '.') != NULL((void*)0))
205 {
206 *newstring = 0;
207 return (name);
208 }
209 else
210 {
211 char hostnamebuf[80];
212 char *firstDot;
213
214 gethostname (hostnamebuf, sizeof hostnamebuf);
215 firstDot = strchr (hostnamebuf, '.');
216
217 if (!firstDot)
218 {
219 *newstring = 0;
220 return (name);
221 }
222 else
223 {
224 char *newptr;
225
226 if (asprintf (&newptr, "%s.%s", name, firstDot + 1) == -1) {
227 *newstring = 0;
228 return NULL((void*)0);
229 }
230 *newstring = 1;
231 return (newptr);
232 }
233 }
234}
235
236
237
238static void
239FinishSaveYourself(WinInfo *winInfo, Boolint has_WM_SAVEYOURSELF)
240{
241 SmProp prop1, prop2, prop3, *props[3];
242 SmPropValue prop1val, prop2val, prop3val;
243 int i;
244
245 if (!winInfo->got_first_save_yourself)
246 {
247 char userId[20], restartService[80];
248 char *fullyQuantifiedName;
249 int newstring;
250
251 prop1.name = SmProgram"Program";
252 prop1.type = SmARRAY8"ARRAY8";
253 prop1.num_vals = 1;
254 prop1.vals = &prop1val;
255 prop1val.value = (SmPointer) winInfo->wm_command[0];
256 prop1val.length = strlen (winInfo->wm_command[0]);
257
258 snprintf (userId, sizeof(userId), "%ld", (long)getuid())__builtin___snprintf_chk (userId, sizeof(userId), 0, __builtin_object_size
(userId, 2 > 1 ? 1 : 0), "%ld", (long)getuid())
;
259 prop2.name = SmUserID"UserID";
260 prop2.type = SmARRAY8"ARRAY8";
261 prop2.num_vals = 1;
262 prop2.vals = &prop2val;
263 prop2val.value = (SmPointer) userId;
264 prop2val.length = strlen (userId);
265
266 fullyQuantifiedName = CheckFullyQuantifiedName (
267 (char *) winInfo->wm_client_machine.value, &newstring);
268 snprintf (restartService, sizeof(restartService),__builtin___snprintf_chk (restartService, sizeof(restartService
), 0, __builtin_object_size (restartService, 2 > 1 ? 1 : 0
), "rstart-rsh/%s", fullyQuantifiedName)
269 "rstart-rsh/%s", fullyQuantifiedName)__builtin___snprintf_chk (restartService, sizeof(restartService
), 0, __builtin_object_size (restartService, 2 > 1 ? 1 : 0
), "rstart-rsh/%s", fullyQuantifiedName)
;
270 if (newstring)
271 free (fullyQuantifiedName);
272
273 prop3.name = "_XC_RestartService";
274 prop3.type = SmLISTofARRAY8"LISTofARRAY8";
275 prop3.num_vals = 1;
276 prop3.vals = &prop3val;
277 prop3val.value = (SmPointer) restartService;
278 prop3val.length = strlen (restartService);
279
280 props[0] = &prop1;
281 props[1] = &prop2;
282 props[2] = &prop3;
283
284 SmcSetProperties (winInfo->smc_conn, 3, props);
285
286 winInfo->got_first_save_yourself = 1;
287 }
288
289 prop1.name = SmRestartCommand"RestartCommand";
290 prop1.type = SmLISTofARRAY8"LISTofARRAY8";
291 prop1.num_vals = winInfo->wm_command_count;
292
293 prop1.vals = (SmPropValue *) malloc (
294 winInfo->wm_command_count * sizeof (SmPropValue));
295
296 if (!prop1.vals)
297 {
298 SmcSaveYourselfDone (winInfo->smc_conn, False0);
299 return;
300 }
301
302 for (i = 0; i < winInfo->wm_command_count; i++)
303 {
304 prop1.vals[i].value = (SmPointer) winInfo->wm_command[i];
305 prop1.vals[i].length = strlen (winInfo->wm_command[i]);
306 }
307
308 prop2.name = SmCloneCommand"CloneCommand";
309 prop2.type = SmLISTofARRAY8"LISTofARRAY8";
310 prop2.num_vals = winInfo->wm_command_count;
311 prop2.vals = prop1.vals;
312
313 props[0] = &prop1;
314 props[1] = &prop2;
315
316 SmcSetProperties (winInfo->smc_conn, 2, props);
317
318 free ((char *) prop1.vals);
319
320 /*
321 * If the client doesn't support WM_SAVE_YOURSELF, we should
322 * return failure for the save, since we really don't know if
323 * the application needed to save state.
324 */
325
326 SmcSaveYourselfDone (winInfo->smc_conn, has_WM_SAVEYOURSELF);
327}
328
329
330
331static void
332SaveYourselfCB(SmcConn smcConn, SmPointer clientData, int saveType,
333 Boolint shutdown, int interactStyle, Boolint fast)
334{
335 WinInfo *winInfo = (WinInfo *) clientData;
336
337 if (!winInfo->has_save_yourself)
338 {
339 FinishSaveYourself (winInfo, False0);
340 }
341 else
342 {
343 XClientMessageEvent saveYourselfMessage;
344
345
346 /* Send WM_SAVE_YOURSELF */
347
348 saveYourselfMessage.type = ClientMessage33;
349 saveYourselfMessage.window = winInfo->window;
350 saveYourselfMessage.message_type = wmProtocolsAtom;
351 saveYourselfMessage.format = 32;
352 saveYourselfMessage.data.l[0] = wmSaveYourselfAtom;
353 saveYourselfMessage.data.l[1] = CurrentTime0L;
354
355 if (XSendEvent (disp, winInfo->window, False0, NoEventMask0L,
356 (XEvent *) &saveYourselfMessage))
357 {
358 winInfo->waiting_for_update = 1;
359
360 if (debug)
361 {
362 printf ("Sent SAVE YOURSELF to 0x%x\n",
363 (unsigned int)winInfo->window);
364 printf ("\n");
365 }
366 }
367 else
368 {
369 if (debug)
370 {
371 printf ("Failed to send SAVE YOURSELF to 0x%x\n",
372 (unsigned int)winInfo->window);
373 printf ("\n");
374 }
375 }
376 }
377}
378
379
380
381static void
382DieCB(SmcConn smcConn, SmPointer clientData)
383{
384 WinInfo *winInfo = (WinInfo *) clientData;
385
386 SmcCloseConnection (winInfo->smc_conn, 0, NULL((void*)0));
387 winInfo->smc_conn = NULL((void*)0);
388 XtRemoveInput (winInfo->input_id);
389
390 /* Now tell the client to die */
391
392 if (debug)
393 printf ("Trying to kill 0x%x\n", (unsigned int)winInfo->window);
394
395 XSync (disp, 0);
396 XKillClient (disp, winInfo->window);
397 XSync (disp, 0);
398
399
400 /*
401 * Proxy must exit when all clients die, and the proxy itself
402 * must have received a Die.
403 */
404
405 die_count++;
406
407 if (die_count == proxy_count && ok_to_die)
408 {
409 exit (0);
410 }
411}
412
413
414
415static void
416SaveCompleteCB(SmcConn smcConn, SmPointer clientData)
417{
418 /*
419 * Nothing to do here.
420 */
421}
422
423
424
425static void
426ShutdownCancelledCB(SmcConn smcConn, SmPointer clientData)
427{
428 /*
429 * Since we did not request to interact or request save yourself
430 * phase 2, we know we already sent the save yourself done, so
431 * there is nothing to do here.
432 */
433}
434
435
436
437static void
438ProcessIceMsgProc(XtPointer client_data, int *source, XtInputId *id)
439{
440 IceConn ice_conn = (IceConn) client_data;
441
442 IceProcessMessages (ice_conn, NULL((void*)0), NULL((void*)0));
443}
444
445
446
447static void
448NullIceErrorHandler(IceConn iceConn, Boolint swap, int offendingMinorOpcode,
449 unsigned long offendingSequence, int errorClass,
450 int severity, IcePointer values)
451{
452 return;
453}
454
455
456static void
457ConnectClientToSM(WinInfo *winInfo)
458{
459 char errorMsg[256];
460 unsigned long mask;
461 SmcCallbacks callbacks;
462 IceConn ice_conn;
463 char *prevId;
464
465 mask = SmcSaveYourselfProcMask(1L << 0) | SmcDieProcMask(1L << 1) |
466 SmcSaveCompleteProcMask(1L << 2) | SmcShutdownCancelledProcMask(1L << 3);
467
468 callbacks.save_yourself.callback = SaveYourselfCB;
469 callbacks.save_yourself.client_data = (SmPointer) winInfo;
470
471 callbacks.die.callback = DieCB;
472 callbacks.die.client_data = (SmPointer) winInfo;
473
474 callbacks.save_complete.callback = SaveCompleteCB;
475 callbacks.save_complete.client_data = (SmPointer) winInfo;
476
477 callbacks.shutdown_cancelled.callback = ShutdownCancelledCB;
478 callbacks.shutdown_cancelled.client_data = (SmPointer) winInfo;
479
480 prevId = LookupClientID (winInfo);
481
482 /*
483 * In case a protocol error occurs when opening the connection,
484 * (e.g. an authentication error), we set a null error handler
485 * before the open, then restore the default handler after the open.
486 */
487
488 IceSetErrorHandler (NullIceErrorHandler);
489
490 winInfo->smc_conn = SmcOpenConnection (
491 NULL((void*)0), /* use SESSION_MANAGER env */
492 (SmPointer) winInfo, /* force a new connection */
493 SmProtoMajor1,
494 SmProtoMinor0,
495 mask,
496 &callbacks,
497 prevId,
498 &winInfo->client_id,
499 256, errorMsg);
500
501 IceSetErrorHandler (NULL((void*)0));
502
503 if (winInfo->smc_conn == NULL((void*)0))
504 return;
505
506 ice_conn = SmcGetIceConnection (winInfo->smc_conn);
507
508 winInfo->input_id = XtAppAddInput (
509 appContext,
510 IceConnectionNumber (ice_conn),
511 (XtPointer) XtInputReadMask(1L<<0),
512 ProcessIceMsgProc,
513 (XtPointer) ice_conn);
514
515 if (debug)
516 {
517 printf ("Connected to SM, window = 0x%x\n",
518 (unsigned int)winInfo->window);
519 printf ("\n");
520 }
521
522 proxy_count++;
523}
524
525
526
527static int
528MyErrorHandler(Display *display, XErrorEvent *event)
529{
530 caught_error = 1;
531 return 0;
532}
533
534
535
536static Boolint
537LookupWindow(Window window, WinInfo **ptr_ret, WinInfo **prev_ptr_ret)
538{
539 WinInfo *ptr, *prev;
540
541 ptr = win_head;
542 prev = NULL((void*)0);
543
544 while (ptr)
545 {
546 if (ptr->window == window)
547 break;
548 else
549 {
550 prev = ptr;
551 ptr = ptr->next;
552 }
553 }
554
555 if (ptr)
556 {
557 if (ptr_ret)
558 *ptr_ret = ptr;
559 if (prev_ptr_ret)
560 *prev_ptr_ret = prev;
561 return (1);
562 }
563 else
564 return (0);
565}
566
567
568
569static WinInfo *
570AddNewWindow(Window window)
571{
572 WinInfo *newptr;
573
574 if (LookupWindow (window, NULL((void*)0), NULL((void*)0)))
575 return (NULL((void*)0));
576
577 newptr = (WinInfo *) malloc (sizeof (WinInfo));
578
579 if (newptr == NULL((void*)0))
580 return (NULL((void*)0));
581
582 newptr->next = win_head;
583 win_head = newptr;
584
585 newptr->window = window;
586 newptr->smc_conn = NULL((void*)0);
587 newptr->tested_for_sm_client_id = 0;
588 newptr->client_id = NULL((void*)0);
589 newptr->wm_command = NULL((void*)0);
590 newptr->wm_command_count = 0;
591 newptr->class.res_name = NULL((void*)0);
592 newptr->class.res_class = NULL((void*)0);
593 newptr->wm_name = NULL((void*)0);
594 newptr->wm_client_machine.value = NULL((void*)0);
595 newptr->wm_client_machine.nitems = 0;
596 newptr->has_save_yourself = 0;
597 newptr->waiting_for_update = 0;
598 newptr->got_first_save_yourself = 0;
599
600 return (newptr);
601}
602
603
604
605static void
606RemoveWindow(WinInfo *winptr)
607{
608 WinInfo *ptr, *prev;
609
610 if (LookupWindow (winptr->window, &ptr, &prev))
611 {
612 if (prev == NULL((void*)0))
613 win_head = ptr->next;
614 else
615 prev->next = ptr->next;
616
617 if (ptr->client_id)
618 free (ptr->client_id);
619
620 if (ptr->wm_command)
621 XFreeStringList (ptr->wm_command);
622
623 if (ptr->wm_name)
624 XFree (ptr->wm_name);
625
626 if (ptr->wm_client_machine.value)
627 XFree (ptr->wm_client_machine.value);
628
629 if (ptr->class.res_name)
630 XFree (ptr->class.res_name);
631
632 if (ptr->class.res_class)
633 XFree (ptr->class.res_class);
634
635 free ((char *) ptr);
636 }
637}
638
639
640
641static void
642Got_WM_STATE(WinInfo *winptr)
643{
644 WinInfo *leader_winptr;
645
646 /*
647 * If we already got WM_STATE and tested for SM_CLIENT_ID, we
648 * shouldn't do it again.
649 */
650
651 if (winptr->tested_for_sm_client_id)
652 {
653 return;
654 }
655
656
657 /*
658 * Set a null error handler, in case this window goes away
659 * behind our back.
660 */
661
662 caught_error = 0;
663 XSetErrorHandler (MyErrorHandler);
664
665
666 /*
667 * Get the client leader window.
668 */
669
670 leader_winptr = GetClientLeader (winptr);
671
672 if (caught_error)
673 {
674 caught_error = 0;
675 RemoveWindow (winptr);
676 XSetErrorHandler (NULL((void*)0));
677 return;
678 }
679
680
681 /*
682 * If we already checked for SM_CLIENT_ID on the client leader
683 * window, don't do it again.
684 */
685
686 if (!leader_winptr || leader_winptr->tested_for_sm_client_id)
687 {
688 caught_error = 0;
689 XSetErrorHandler (NULL((void*)0));
690 return;
691 }
692
693 leader_winptr->tested_for_sm_client_id = 1;
694
695 if (!HasXSMPsupport (leader_winptr->window))
696 {
697 XFetchName (disp, leader_winptr->window, &leader_winptr->wm_name);
698
699 XGetCommand (disp, leader_winptr->window,
700 &leader_winptr->wm_command,
701 &leader_winptr->wm_command_count);
702
703 XGetClassHint (disp, leader_winptr->window, &leader_winptr->class);
704
705 XGetWMClientMachine (disp, leader_winptr->window,
706 &leader_winptr->wm_client_machine);
707
708 if (leader_winptr->wm_name != NULL((void*)0) &&
709 leader_winptr->wm_command != NULL((void*)0) &&
710 leader_winptr->wm_command_count > 0 &&
711 leader_winptr->class.res_name != NULL((void*)0) &&
712 leader_winptr->class.res_class != NULL((void*)0) &&
713 leader_winptr->wm_client_machine.value != NULL((void*)0) &&
714 leader_winptr->wm_client_machine.nitems != 0)
715 {
716 leader_winptr->has_save_yourself =
717 HasSaveYourself (leader_winptr->window);
718
719 ConnectClientToSM (leader_winptr);
720 }
721 }
722
723 XSync (disp, 0);
724 XSetErrorHandler (NULL((void*)0));
725
726 if (caught_error)
727 {
728 caught_error = 0;
729 RemoveWindow (leader_winptr);
730 }
731}
732
733
734
735static void
736HandleCreate(XCreateWindowEvent *event)
737{
738 Atom actual_type;
739 int actual_format;
740 unsigned long nitems, bytesafter;
741 unsigned long *datap = NULL((void*)0);
742 WinInfo *winptr;
743 Boolint got_wm_state = 0;
744
745 /*
746 * We are waiting for all proxy connections to close so we can die.
747 * Don't handle new connections.
748 */
749
750 if (ok_to_die)
751 return;
752
753
754 /*
755 * Add the new window
756 */
757
758 if ((winptr = AddNewWindow (event->window)) == NULL((void*)0))
759 return;
760
761
762 /*
763 * Right after the window was created, it might have been destroyed,
764 * so the following Xlib calls might fail. Need to catch the error
765 * by installing an error handler.
766 */
767
768 caught_error = 0;
769 XSetErrorHandler (MyErrorHandler);
770
771
772 /*
773 * Select for Property Notify on the window so we can determine
774 * when WM_STATE is defined. To avoid a race condition, we must
775 * do this _before_ we check for WM_STATE right now.
776 *
777 * Select for Substructure Notify so we can determine when the
778 * window is destroyed.
779 */
780
781 XSelectInput (disp, event->window,
782 SubstructureNotifyMask(1L<<19) | PropertyChangeMask(1L<<22));
783
784
785 /*
786 * WM_STATE may already be there. Check now.
787 */
788
789 if (XGetWindowProperty (disp, event->window, wmStateAtom,
790 0L, 2L, False0, AnyPropertyType0L,
791 &actual_type, &actual_format, &nitems, &bytesafter,
792 (unsigned char **) &datap) == Success0 && datap)
793 {
794 if (nitems > 0)
795 got_wm_state = 1;
796
797 if (datap)
798 XFree ((char *) datap);
799 }
800
801 XSync (disp, 0);
802 XSetErrorHandler (NULL((void*)0));
803
804 if (caught_error)
805 {
806 caught_error = 0;
807 RemoveWindow (winptr);
808 }
809 else if (got_wm_state)
810 {
811 Got_WM_STATE (winptr);
812 }
813}
814
815
816
817static void
818HandleDestroy(XDestroyWindowEvent *event)
819{
820 WinInfo *winptr;
821
822 if (LookupWindow (event->window, &winptr, NULL((void*)0)))
823 {
824 if (winptr->smc_conn)
825 {
826 SmcCloseConnection (winptr->smc_conn, 0, NULL((void*)0));
827 XtRemoveInput (winptr->input_id);
828 proxy_count--;
829 }
830
831 if (debug)
832 {
833 printf ("Removed window (window = 0x%x)\n",
834 (unsigned int)winptr->window);
835 printf ("\n");
836 }
837
838 RemoveWindow (winptr);
839 }
840}
841
842
843
844static void
845HandleUpdate(XPropertyEvent *event)
846{
847 Window window = event->window;
848 WinInfo *winptr;
849
850 if (!LookupWindow (window, &winptr, NULL((void*)0)))
851 return;
852
853 if (event->atom == wmStateAtom)
854 {
855 Got_WM_STATE (winptr);
856 }
857 else if (event->atom == XA_WM_COMMAND((Atom) 34) && winptr->waiting_for_update)
858 {
859 /* Finish off the Save Yourself */
860
861 if (winptr->wm_command)
862 {
863 XFreeStringList (winptr->wm_command);
864 winptr->wm_command = NULL((void*)0);
865 winptr->wm_command_count = 0;
866 }
867
868 XGetCommand (disp, window,
869 &winptr->wm_command,
870 &winptr->wm_command_count);
871
872 winptr->waiting_for_update = 0;
873 FinishSaveYourself (winptr, True1);
874 }
875}
876
877
878
879static void
880ProxySaveYourselfPhase2CB(SmcConn smcConn, SmPointer clientData)
881{
882 char *filename;
883 Boolint success = True1;
884 SmProp prop1, prop2, prop3, *props[3];
885 SmPropValue prop1val, prop2val, prop3val;
886 char *discardCommand;
887 int numVals, i;
888 static int first_time = 1;
889
890 if (first_time)
1
Taking true branch
891 {
892 char userId[20];
893 char hint = SmRestartIfRunning0;
894
895 prop1.name = SmProgram"Program";
896 prop1.type = SmARRAY8"ARRAY8";
897 prop1.num_vals = 1;
898 prop1.vals = &prop1val;
899 prop1val.value = Argv[0];
900 prop1val.length = strlen (Argv[0]);
901
902 snprintf (userId, sizeof(userId), "%ld", (long)getuid())__builtin___snprintf_chk (userId, sizeof(userId), 0, __builtin_object_size
(userId, 2 > 1 ? 1 : 0), "%ld", (long)getuid())
;
903 prop2.name = SmUserID"UserID";
904 prop2.type = SmARRAY8"ARRAY8";
905 prop2.num_vals = 1;
906 prop2.vals = &prop2val;
907 prop2val.value = (SmPointer) userId;
908 prop2val.length = strlen (userId);
909
910 prop3.name = SmRestartStyleHint"RestartStyleHint";
911 prop3.type = SmCARD8"CARD8";
912 prop3.num_vals = 1;
913 prop3.vals = &prop3val;
914 prop3val.value = (SmPointer) &hint;
915 prop3val.length = 1;
916
917 props[0] = &prop1;
918 props[1] = &prop2;
919 props[2] = &prop3;
920
921 SmcSetProperties (smcConn, 3, props);
922
923 first_time = 0;
924 }
925
926 if ((filename = WriteProxyFile ()) == NULL((void*)0))
2
Taking false branch
927 {
928 success = False0;
929 goto finishUp;
930 }
931
932 prop1.name = SmRestartCommand"RestartCommand";
933 prop1.type = SmLISTofARRAY8"LISTofARRAY8";
934
935 prop1.vals = (SmPropValue *) malloc (
3
Memory is allocated
936 (Argc + 4) * sizeof (SmPropValue));
937
938 if (!prop1.vals)
4
Taking false branch
939 {
940 success = False0;
941 goto finishUp;
942 }
943
944 numVals = 0;
945
946 for (i = 0; i < Argc; i++)
5
Assuming 'i' is >= 'Argc'
6
Loop condition is false. Execution continues on line 960
947 {
948 if (strcmp (Argv[i], "-clientId") == 0 ||
949 strcmp (Argv[i], "-restore") == 0)
950 {
951 i++;
952 }
953 else
954 {
955 prop1.vals[numVals].value = (SmPointer) Argv[i];
956 prop1.vals[numVals++].length = strlen (Argv[i]);
957 }
958 }
959
960 prop1.vals[numVals].value = (SmPointer) "-clientId";
961 prop1.vals[numVals++].length = 9;
962
963 prop1.vals[numVals].value = (SmPointer) proxy_clientId;
964 prop1.vals[numVals++].length = strlen (proxy_clientId);
965
966 prop1.vals[numVals].value = (SmPointer) "-restore";
967 prop1.vals[numVals++].length = 8;
968
969 prop1.vals[numVals].value = (SmPointer) filename;
970 prop1.vals[numVals++].length = strlen (filename);
971
972 prop1.num_vals = numVals;
973
974
975 if (asprintf (&discardCommand, "rm %s", filename) == -1) {
7
Taking true branch
976 success = False0;
8
Within the expansion of the macro 'False':
a
Potential leak of memory pointed to by 'prop1.vals'
977 goto finishUp;
978 }
979 prop2.name = SmDiscardCommand"DiscardCommand";
980 prop2.type = SmARRAY8"ARRAY8";
981 prop2.num_vals = 1;
982 prop2.vals = &prop2val;
983 prop2val.value = (SmPointer) discardCommand;
984 prop2val.length = strlen (discardCommand);
985
986 props[0] = &prop1;
987 props[1] = &prop2;
988
989 SmcSetProperties (smcConn, 2, props);
990 free ((char *) prop1.vals);
991 free (discardCommand);
992
993 finishUp:
994
995 SmcSaveYourselfDone (smcConn, success);
996 sent_save_done = 1;
997
998 if (filename)
999 free (filename);
1000}
1001
1002
1003
1004static void
1005ProxySaveYourselfCB(SmcConn smcConn, SmPointer clientData, int saveType,
1006 Boolint shutdown, int interactStyle, Boolint fast)
1007{
1008 /*
1009 * We want the proxy to respond to the Save Yourself after all
1010 * the regular XSMP clients have finished with the save (and possibly
1011 * interacted with the user).
1012 */
1013
1014 if (!SmcRequestSaveYourselfPhase2 (smcConn,
1015 ProxySaveYourselfPhase2CB, NULL((void*)0)))
1016 {
1017 SmcSaveYourselfDone (smcConn, False0);
1018 sent_save_done = 1;
1019 }
1020 else
1021 sent_save_done = 0;
1022}
1023
1024
1025
1026static void
1027ProxyDieCB(SmcConn smcConn, SmPointer clientData)
1028{
1029 SmcCloseConnection (proxy_smcConn, 0, NULL((void*)0));
1030 XtRemoveInput (proxy_iceInputId);
1031
1032 if (die_count == proxy_count)
1033 exit (0);
1034 else
1035 ok_to_die = 1;
1036}
1037
1038
1039
1040static void
1041ProxySaveCompleteCB(SmcConn smcConn, SmPointer clientData)
1042{
1043 ;
1044}
1045
1046
1047
1048static void
1049ProxyShutdownCancelledCB(SmcConn smcConn, SmPointer clientData)
1050{
1051 if (!sent_save_done)
1052 {
1053 SmcSaveYourselfDone (smcConn, False0);
1054 sent_save_done = 1;
1055 }
1056}
1057
1058
1059
1060static Statusint
1061ConnectProxyToSM(char *previous_id)
1062{
1063 char errorMsg[256];
1064 unsigned long mask;
1065 SmcCallbacks callbacks;
1066 IceConn iceConn;
1067
1068 mask = SmcSaveYourselfProcMask(1L << 0) | SmcDieProcMask(1L << 1) |
1069 SmcSaveCompleteProcMask(1L << 2) | SmcShutdownCancelledProcMask(1L << 3);
1070
1071 callbacks.save_yourself.callback = ProxySaveYourselfCB;
1072 callbacks.save_yourself.client_data = (SmPointer) NULL((void*)0);
1073
1074 callbacks.die.callback = ProxyDieCB;
1075 callbacks.die.client_data = (SmPointer) NULL((void*)0);
1076
1077 callbacks.save_complete.callback = ProxySaveCompleteCB;
1078 callbacks.save_complete.client_data = (SmPointer) NULL((void*)0);
1079
1080 callbacks.shutdown_cancelled.callback = ProxyShutdownCancelledCB;
1081 callbacks.shutdown_cancelled.client_data = (SmPointer) NULL((void*)0);
1082
1083 proxy_smcConn = SmcOpenConnection (
1084 NULL((void*)0), /* use SESSION_MANAGER env */
1085 (SmPointer) appContext,
1086 SmProtoMajor1,
1087 SmProtoMinor0,
1088 mask,
1089 &callbacks,
1090 previous_id,
1091 &proxy_clientId,
1092 256, errorMsg);
1093
1094 if (proxy_smcConn == NULL((void*)0))
1095 return (0);
1096
1097 iceConn = SmcGetIceConnection (proxy_smcConn);
1098
1099 proxy_iceInputId = XtAppAddInput (
1100 appContext,
1101 IceConnectionNumber (iceConn),
1102 (XtPointer) XtInputReadMask(1L<<0),
1103 ProcessIceMsgProc,
1104 (XtPointer) iceConn);
1105
1106 return (1);
1107}
1108
1109
1110
1111static void
1112CheckForExistingWindows(Window root)
1113{
1114 Window dontCare1, dontCare2, *children, client_window;
1115 unsigned int nchildren, i;
1116 XCreateWindowEvent event;
1117
1118 /*
1119 * We query the root tree for all windows created thus far.
1120 * Note that at any moment after XQueryTree is called, a
1121 * window may be deleted. So we must take extra care to make
1122 * sure a window really exists.
1123 */
1124
1125 XQueryTree (disp, root, &dontCare1, &dontCare2, &children, &nchildren);
1126
1127 for (i = 0; i < nchildren; i++)
1128 {
1129 event.window = children[i];
1130
1131 HandleCreate (&event);
1132
1133 caught_error = 0;
1134 XSetErrorHandler (MyErrorHandler);
1135
1136 client_window = XmuClientWindow (disp, children[i]);
1137
1138 XSetErrorHandler (NULL((void*)0));
1139
1140 if (!caught_error && client_window != children[i])
1141 {
1142 event.window = client_window;
1143 HandleCreate (&event);
1144 }
1145 }
1146}
1147
1148
1149
1150int
1151main (int argc, char *argv[])
1152{
1153 char *restore_filename = NULL((void*)0);
1154 char *client_id = NULL((void*)0);
1155 int i, zero = 0;
1156
1157 Argc = argc;
1158 Argv = argv;
1159
1160 for (i = 1; i < argc; i++)
1161 {
1162 if (argv[i][0] == '-')
1163 {
1164 switch (argv[i][1])
1165 {
1166 case 'd': /* -debug */
1167 debug = 1;
1168 continue;
1169
1170 case 'c': /* -clientId */
1171 if (++i >= argc) {
1172 fprintf (stderr__stderrp, "%s: -clientId requires an argument\n",
1173 argv[0]);
1174 goto usage;
1175 }
1176 client_id = argv[i];
1177 continue;
1178
1179 case 'r': /* -restore */
1180 if (++i >= argc) {
1181 fprintf (stderr__stderrp, "%s: -restore requires an argument\n",
1182 argv[0]);
1183 goto usage;
1184 }
1185 restore_filename = argv[i];
1186 continue;
1187
1188 case 'v':
1189 puts (PACKAGE_STRING"smproxy 1.0.6");
1190 exit (0);
1191 }
1192 }
1193
1194 fprintf (stderr__stderrp, "%s: unrecognized argument: %s\n", argv[0], argv[i]);
1195
1196 usage:
1197
1198 fprintf (stderr__stderrp,
1199 "usage: %s [-clientId id] [-restore file] [-debug] [-version]\n",
1200 argv[0]);
1201 exit (1);
1202 }
1203
1204
1205 XtToolkitInitialize ();
1206 appContext = XtCreateApplicationContext ();
1207
1208 if (!(disp = XtOpenDisplay (appContext, NULL((void*)0), "SM-PROXY", "SM-PROXY",
1209 NULL((void*)0), 0, &zero, NULL((void*)0))))
1210 {
1211 fprintf (stderr__stderrp, "smproxy: unable to open display\n");
1212 exit (1);
1213 }
1214
1215 if (restore_filename)
1216 ReadProxyFile (restore_filename);
1217
1218 if (!ConnectProxyToSM (client_id))
1219 {
1220 fprintf (stderr__stderrp, "smproxy: unable to connect to session manager\n");
1221 exit (1);
1222 }
1223
1224 wmProtocolsAtom = XInternAtom (disp, "WM_PROTOCOLS", False0);
1225 wmSaveYourselfAtom = XInternAtom (disp, "WM_SAVE_YOURSELF", False0);
1226 wmStateAtom = XInternAtom (disp, "WM_STATE", False0);
1227 smClientIdAtom = XInternAtom (disp, "SM_CLIENT_ID", False0);
1228 wmClientLeaderAtom = XInternAtom (disp, "WM_CLIENT_LEADER", False0);
1229
1230 for (i = 0; i < ScreenCount (disp)(((_XPrivDisplay)(disp))->nscreens); i++)
1231 {
1232 Window root = RootWindow (disp, i)((&((_XPrivDisplay)(disp))->screens[i])->root);
1233 XSelectInput (disp, root, SubstructureNotifyMask(1L<<19) | PropertyChangeMask(1L<<22));
1234 CheckForExistingWindows (root);
1235 }
1236
1237 while (1)
1238 {
1239 XEvent event;
1240
1241 XtAppNextEvent (appContext, &event);
1242
1243 switch (event.type)
1244 {
1245 case CreateNotify16:
1246 HandleCreate (&event.xcreatewindow);
1247 break;
1248
1249 case DestroyNotify17:
1250 HandleDestroy (&event.xdestroywindow);
1251 break;
1252
1253 case PropertyNotify28:
1254 HandleUpdate (&event.xproperty);
1255 break;
1256
1257 default:
1258 XtDispatchEvent (&event);
1259 break;
1260 }
1261 }
1262 exit(0);
1263}