dsniff  2.4b2
About: A collection of tools for network auditing
  Fossies Dox: dsniff-2.4b2.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

remote.c
Go to the documentation of this file.
1 /* -*- Mode:C; tab-width: 8 -*-
2  * remote.c --- remote control of Netscape Navigator for Unix.
3  * version 1.1.3, for Netscape Navigator 1.1 and newer.
4  *
5  * Copyright 1996 Netscape Communications Corporation, all rights reserved.
6  * Created: Jamie Zawinski <jwz@netscape.com>, 24-Dec-94.
7  *
8  * Permission to use, copy, modify, distribute, and sell this software and its
9  * documentation for any purpose is hereby granted without fee, provided that
10  * the above copyright notice appear in all copies and that both that
11  * copyright notice and this permission notice appear in supporting
12  * documentation. No representations are made about the suitability of this
13  * software for any purpose. It is provided "as is" without express or
14  * implied warranty.
15  *
16  * To compile:
17  *
18  * cc -o netscape-remote remote.c -DSTANDALONE -lXmu -lX11
19  *
20  * To use:
21  *
22  * netscape-remote -help
23  *
24  * Documentation for the protocol which this code implements may be found at:
25  *
26  * http://home.netscape.com/newsref/std/x-remote.html
27  *
28  * Bugs and commentary to x_cbug@netscape.com.
29  */
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <string.h>
35 
36 #include <X11/Xlib.h>
37 #include <X11/Xatom.h>
38 #include <X11/Xmu/WinUtil.h> /* for XmuClientWindow() */
39 
40 
41 /* vroot.h is a header file which lets a client get along with `virtual root'
42  window managers like swm, tvtwm, olvwm, etc. If you don't have this header
43  file, you can find it at "http://home.netscape.com/newsref/std/vroot.h".
44  If you don't care about supporting virtual root window managers, you can
45  comment this line out.
46  */
47 #include "vroot.h"
48 
49 
50 #ifdef STANDALONE
51  static const char *progname = 0;
52  static const char *expected_mozilla_version = "1.1";
53 #else /* !STANDALONE */
54  extern const char *progname;
55  extern const char *expected_mozilla_version;
56 #endif /* !STANDALONE */
57 
58 #define MOZILLA_VERSION_PROP "_MOZILLA_VERSION"
59 #define MOZILLA_LOCK_PROP "_MOZILLA_LOCK"
60 #define MOZILLA_COMMAND_PROP "_MOZILLA_COMMAND"
61 #define MOZILLA_RESPONSE_PROP "_MOZILLA_RESPONSE"
62 static Atom XA_MOZILLA_VERSION = 0;
63 static Atom XA_MOZILLA_LOCK = 0;
64 static Atom XA_MOZILLA_COMMAND = 0;
65 static Atom XA_MOZILLA_RESPONSE = 0;
66 
67 static void
69 {
70  if (! XA_MOZILLA_VERSION)
71  XA_MOZILLA_VERSION = XInternAtom (dpy, MOZILLA_VERSION_PROP, False);
72  if (! XA_MOZILLA_LOCK)
73  XA_MOZILLA_LOCK = XInternAtom (dpy, MOZILLA_LOCK_PROP, False);
74  if (! XA_MOZILLA_COMMAND)
75  XA_MOZILLA_COMMAND = XInternAtom (dpy, MOZILLA_COMMAND_PROP, False);
76  if (! XA_MOZILLA_RESPONSE)
77  XA_MOZILLA_RESPONSE = XInternAtom (dpy, MOZILLA_RESPONSE_PROP, False);
78 }
79 
80 static Window
82 {
83  int i;
84  Window root = RootWindowOfScreen (DefaultScreenOfDisplay (dpy));
85  Window root2, parent, *kids;
86  unsigned int nkids;
87  Window result = 0;
88  Window tenative = 0;
89  unsigned char *tenative_version = 0;
90 
91  if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
92  {
93  fprintf (stderr, "%s: XQueryTree failed on display %s\n", progname,
94  DisplayString (dpy));
95  exit (2);
96  }
97 
98  /* root != root2 is possible with virtual root WMs. */
99 
100  if (! (kids && nkids))
101  {
102  fprintf (stderr, "%s: root window has no children on display %s\n",
103  progname, DisplayString (dpy));
104  exit (2);
105  }
106 
107  for (i = nkids-1; i >= 0; i--)
108  {
109  Atom type;
110  int format, status;
111  unsigned long nitems, bytesafter;
112  unsigned char *version = 0;
113  Window w;
114 
115  w = XmuClientWindow (dpy, kids[i]);
116  status = XGetWindowProperty (dpy, w, XA_MOZILLA_VERSION,
117  0, (65536 / sizeof (long)),
118  False, XA_STRING,
119  &type, &format, &nitems, &bytesafter,
120  &version);
121  if (! version)
122  continue;
123  if (strcmp ((char *) version, expected_mozilla_version) &&
124  !tenative)
125  {
126  tenative = w;
127  tenative_version = version;
128  continue;
129  }
130  XFree (version);
131  if (status == Success && type != None)
132  {
133  result = w;
134  break;
135  }
136  }
137 
138  if (result && tenative)
139  {
140  fprintf (stderr,
141  "%s: warning: both version %s (0x%x) and version\n"
142  "\t%s (0x%x) are running. Using version %s.\n",
143  progname, tenative_version, (unsigned int) tenative,
144  expected_mozilla_version, (unsigned int) result,
146  XFree (tenative_version);
147  return result;
148  }
149  else if (tenative)
150  {
151 #if 0
152  fprintf (stderr,
153  "%s: warning: expected version %s but found version\n"
154  "\t%s (0x%x) instead.\n",
156  tenative_version, (unsigned int) tenative);
157 #endif
158  XFree (tenative_version);
159  return tenative;
160  }
161  else if (result)
162  {
163  return result;
164  }
165  else
166  {
167  fprintf (stderr, "%s: not running on display %s\n", progname,
168  DisplayString (dpy));
169  exit (1);
170  }
171 }
172 
173 static void
174 mozilla_remote_check_window (Display *dpy, Window window)
175 {
176  Atom type;
177  int format;
178  unsigned long nitems, bytesafter;
179  unsigned char *version = 0;
180  int status = XGetWindowProperty (dpy, window, XA_MOZILLA_VERSION,
181  0, (65536 / sizeof (long)),
182  False, XA_STRING,
183  &type, &format, &nitems, &bytesafter,
184  &version);
185  if (status != Success || !version)
186  {
187  fprintf (stderr, "%s: window 0x%x is not a Netscape window.\n",
188  progname, (unsigned int) window);
189  exit (6);
190  }
191  else if (strcmp ((char *) version, expected_mozilla_version))
192  {
193  fprintf (stderr,
194  "%s: warning: window 0x%x is Netscape version %s;\n"
195  "\texpected version %s.\n",
196  progname, (unsigned int) window,
197  version, expected_mozilla_version);
198  }
199  XFree (version);
200 }
201 
202 
203 static char *lock_data = 0;
204 
205 static void
206 mozilla_remote_obtain_lock (Display *dpy, Window window)
207 {
208  Bool locked = False;
209  Bool waited = False;
210 
211  if (! lock_data)
212  {
213  lock_data = (char *) malloc (255);
214  sprintf (lock_data, "pid%d@", getpid ());
215  if (gethostname (lock_data + strlen (lock_data), 100))
216  {
217  perror ("gethostname");
218  exit (-1);
219  }
220  }
221 
222  do
223  {
224  int result;
225  Atom actual_type;
226  int actual_format;
227  unsigned long nitems, bytes_after;
228  unsigned char *data = 0;
229 
230  XGrabServer (dpy); /* ################################# DANGER! */
231 
232  result = XGetWindowProperty (dpy, window, XA_MOZILLA_LOCK,
233  0, (65536 / sizeof (long)),
234  False, /* don't delete */
235  XA_STRING,
236  &actual_type, &actual_format,
237  &nitems, &bytes_after,
238  &data);
239  if (result != Success || actual_type == None)
240  {
241  /* It's not now locked - lock it. */
242 #ifdef DEBUG_PROPS
243  fprintf (stderr, "%s: (writing " MOZILLA_LOCK_PROP
244  " \"%s\" to 0x%x)\n",
245  progname, lock_data, (unsigned int) window);
246 #endif
247  XChangeProperty (dpy, window, XA_MOZILLA_LOCK, XA_STRING, 8,
248  PropModeReplace, (unsigned char *) lock_data,
249  strlen (lock_data));
250  locked = True;
251  }
252 
253  XUngrabServer (dpy); /* ################################# danger over */
254  XSync (dpy, False);
255 
256  if (! locked)
257  {
258  /* We tried to grab the lock this time, and failed because someone
259  else is holding it already. So, wait for a PropertyDelete event
260  to come in, and try again. */
261 
262  fprintf (stderr, "%s: window 0x%x is locked by %s; waiting...\n",
263  progname, (unsigned int) window, data);
264  waited = True;
265 
266  while (1)
267  {
268  XEvent event;
269  XNextEvent (dpy, &event);
270  if (event.xany.type == DestroyNotify &&
271  event.xdestroywindow.window == window)
272  {
273  fprintf (stderr, "%s: window 0x%x unexpectedly destroyed.\n",
274  progname, (unsigned int) window);
275  exit (6);
276  }
277  else if (event.xany.type == PropertyNotify &&
278  event.xproperty.state == PropertyDelete &&
279  event.xproperty.window == window &&
280  event.xproperty.atom == XA_MOZILLA_LOCK)
281  {
282  /* Ok! Someone deleted their lock, so now we can try
283  again. */
284 #ifdef DEBUG_PROPS
285  fprintf (stderr, "%s: (0x%x unlocked, trying again...)\n",
286  progname, (unsigned int) window);
287 #endif
288  break;
289  }
290  }
291  }
292  if (data)
293  XFree (data);
294  }
295  while (! locked);
296 
297  if (waited)
298  fprintf (stderr, "%s: obtained lock.\n", progname);
299 }
300 
301 
302 static void
303 mozilla_remote_free_lock (Display *dpy, Window window)
304 {
305  int result;
306  Atom actual_type;
307  int actual_format;
308  unsigned long nitems, bytes_after;
309  unsigned char *data = 0;
310 
311 #ifdef DEBUG_PROPS
312  fprintf (stderr, "%s: (deleting " MOZILLA_LOCK_PROP
313  " \"%s\" from 0x%x)\n",
314  progname, lock_data, (unsigned int) window);
315 #endif
316 
317  result = XGetWindowProperty (dpy, window, XA_MOZILLA_LOCK,
318  0, (65536 / sizeof (long)),
319  True, /* atomic delete after */
320  XA_STRING,
321  &actual_type, &actual_format,
322  &nitems, &bytes_after,
323  &data);
324  if (result != Success)
325  {
326  fprintf (stderr, "%s: unable to read and delete " MOZILLA_LOCK_PROP
327  " property\n",
328  progname);
329  return;
330  }
331  else if (!data || !*data)
332  {
333  fprintf (stderr, "%s: invalid data on " MOZILLA_LOCK_PROP
334  " of window 0x%x.\n",
335  progname, (unsigned int) window);
336  return;
337  }
338  else if (strcmp ((char *) data, lock_data))
339  {
340  fprintf (stderr, "%s: " MOZILLA_LOCK_PROP
341  " was stolen! Expected \"%s\", saw \"%s\"!\n",
343  return;
344  }
345 
346  if (data)
347  XFree (data);
348 }
349 
350 
351 static int
352 mozilla_remote_command (Display *dpy, Window window, const char *command,
353  Bool raise_p)
354 {
355  int result = 0;
356  Bool done = False;
357  char *new_command = 0;
358 
359  /* The -noraise option is implemented by passing a "noraise" argument
360  to each command to which it should apply.
361  */
362  if (! raise_p)
363  {
364  char *close;
365  new_command = (char *) malloc (strlen (command) + 20);
366  strcpy (new_command, command);
367  close = strrchr (new_command, ')');
368  if (close)
369  strcpy (close, ", noraise)");
370  else
371  strcat (new_command, "(noraise)");
372  command = new_command;
373  }
374 
375 #ifdef DEBUG_PROPS
376  fprintf (stderr, "%s: (writing " MOZILLA_COMMAND_PROP " \"%s\" to 0x%x)\n",
377  progname, command, (unsigned int) window);
378 #endif
379 
380  XChangeProperty (dpy, window, XA_MOZILLA_COMMAND, XA_STRING, 8,
381  PropModeReplace, (unsigned char *) command,
382  strlen (command));
383 
384  while (!done)
385  {
386  XEvent event;
387  XNextEvent (dpy, &event);
388  if (event.xany.type == DestroyNotify &&
389  event.xdestroywindow.window == window)
390  {
391  /* Print to warn user...*/
392  fprintf (stderr, "%s: window 0x%x was destroyed.\n",
393  progname, (unsigned int) window);
394  result = 6;
395  goto DONE;
396  }
397  else if (event.xany.type == PropertyNotify &&
398  event.xproperty.state == PropertyNewValue &&
399  event.xproperty.window == window &&
400  event.xproperty.atom == XA_MOZILLA_RESPONSE)
401  {
402  Atom actual_type;
403  int actual_format;
404  unsigned long nitems, bytes_after;
405  unsigned char *data = 0;
406 
407  result = XGetWindowProperty (dpy, window, XA_MOZILLA_RESPONSE,
408  0, (65536 / sizeof (long)),
409  True, /* atomic delete after */
410  XA_STRING,
411  &actual_type, &actual_format,
412  &nitems, &bytes_after,
413  &data);
414 #ifdef DEBUG_PROPS
415  if (result == Success && data && *data)
416  {
417  fprintf (stderr, "%s: (server sent " MOZILLA_RESPONSE_PROP
418  " \"%s\" to 0x%x.)\n",
419  progname, data, (unsigned int) window);
420  }
421 #endif
422 
423  if (result != Success)
424  {
425  fprintf (stderr, "%s: failed reading " MOZILLA_RESPONSE_PROP
426  " from window 0x%0x.\n",
427  progname, (unsigned int) window);
428  result = 6;
429  done = True;
430  }
431  else if (!data || strlen((char *) data) < 5)
432  {
433  fprintf (stderr, "%s: invalid data on " MOZILLA_RESPONSE_PROP
434  " property of window 0x%0x.\n",
435  progname, (unsigned int) window);
436  result = 6;
437  done = True;
438  }
439  else if (*data == '1') /* positive preliminary reply */
440  {
441  fprintf (stderr, "%s: %s\n", progname, data + 4);
442  /* keep going */
443  done = False;
444  }
445 #if 1
446  else if (!strncmp ((char *)data, "200", 3)) /* positive completion */
447  {
448  result = 0;
449  done = True;
450  }
451 #endif
452  else if (*data == '2') /* positive completion */
453  {
454  fprintf (stderr, "%s: %s\n", progname, data + 4);
455  result = 0;
456  done = True;
457  }
458  else if (*data == '3') /* positive intermediate reply */
459  {
460  fprintf (stderr, "%s: internal error: "
461  "server wants more information? (%s)\n",
462  progname, data);
463  result = 3;
464  done = True;
465  }
466  else if (*data == '4' || /* transient negative completion */
467  *data == '5') /* permanent negative completion */
468  {
469  fprintf (stderr, "%s: %s\n", progname, data + 4);
470  result = (*data - '0');
471  done = True;
472  }
473  else
474  {
475  fprintf (stderr,
476  "%s: unrecognised " MOZILLA_RESPONSE_PROP
477  " from window 0x%x: %s\n",
478  progname, (unsigned int) window, data);
479  result = 6;
480  done = True;
481  }
482 
483  if (data)
484  XFree (data);
485  }
486 #ifdef DEBUG_PROPS
487  else if (event.xany.type == PropertyNotify &&
488  event.xproperty.window == window &&
489  event.xproperty.state == PropertyDelete &&
490  event.xproperty.atom == XA_MOZILLA_COMMAND)
491  {
492  fprintf (stderr, "%s: (server 0x%x has accepted "
493  MOZILLA_COMMAND_PROP ".)\n",
494  progname, (unsigned int) window);
495  }
496 #endif /* DEBUG_PROPS */
497  }
498 
499  DONE:
500 
501  if (new_command)
502  free (new_command);
503 
504  return result;
505 }
506 
507 int
508 mozilla_remote_commands (Display *dpy, Window window, char **commands)
509 {
510  Bool raise_p = True;
511  int status = 0;
513 
514  if (window == 0)
515  window = mozilla_remote_find_window (dpy);
516  else
518 
519  XSelectInput (dpy, window, (PropertyChangeMask|StructureNotifyMask));
520 
522 
523  while (*commands)
524  {
525  if (!strcmp (*commands, "-raise"))
526  raise_p = True;
527  else if (!strcmp (*commands, "-noraise"))
528  raise_p = False;
529  else
530  status = mozilla_remote_command (dpy, window, *commands, raise_p);
531 
532  if (status != 0)
533  break;
534  commands++;
535  }
536 
537  /* When status = 6, it means the window has been destroyed */
538  /* It is invalid to free the lock when window is destroyed. */
539 
540  if ( status != 6 )
541  mozilla_remote_free_lock (dpy, window);
542 
543  return status;
544 }
545 
546 
547 #ifdef STANDALONE
548 
549 static void
550 usage (void)
551 {
552  fprintf (stderr, "usage: %s [ options ... ]\n\
553  where options include:\n\
554 \n\
555  -help to show this message.\n\
556  -display <dpy> to specify the X server to use.\n\
557  -remote <remote-command> to execute a command in an already-running\n\
558  Netscape process. See the manual for a\n\
559  list of valid commands.\n\
560  -id <window-id> the id of an X window to which the -remote\n\
561  commands should be sent; if unspecified,\n\
562  the first window found will be used.\n\
563  -raise whether following -remote commands should\n\
564  cause the window to raise itself to the top\n\
565  (this is the default.)\n\
566  -noraise the opposite of -raise: following -remote\n\
567  commands will not auto-raise the window.\n\
568 ",
569  progname);
570 }
571 
572 
573 void
574 main (int argc, char **argv)
575 {
576  Display *dpy;
577  char *dpy_string = 0;
578  char **remote_commands = 0;
579  int remote_command_count = 0;
580  int remote_command_size = 0;
581  unsigned long remote_window = 0;
582  Bool sync_p = False;
583  int i;
584 
585  progname = strrchr (argv[0], '/');
586  if (progname)
587  progname++;
588  else
589  progname = argv[0];
590 
591  /* Hack the -help and -version arguments before opening the display. */
592  for (i = 1; i < argc; i++)
593  {
594  if (!strcasecmp (argv [i], "-h") ||
595  !strcasecmp (argv [i], "-help"))
596  {
597  usage ();
598  exit (0);
599  }
600  else if (!strcmp (argv [i], "-d") ||
601  !strcmp (argv [i], "-dpy") ||
602  !strcmp (argv [i], "-disp") ||
603  !strcmp (argv [i], "-display"))
604  {
605  i++;
606  dpy_string = argv [i];
607  }
608  else if (!strcmp (argv [i], "-sync") ||
609  !strcmp (argv [i], "-synchronize"))
610  {
611  sync_p = True;
612  }
613  else if (!strcmp (argv [i], "-remote"))
614  {
615  if (remote_command_count == remote_command_size)
616  {
617  remote_command_size += 20;
618  remote_commands =
619  (remote_commands
620  ? realloc (remote_commands,
621  remote_command_size * sizeof (char *))
622  : calloc (remote_command_size, sizeof (char *)));
623  }
624  i++;
625  if (!argv[i] || *argv[i] == '-' || *argv[i] == 0)
626  {
627  fprintf (stderr, "%s: invalid `-remote' option \"%s\"\n",
628  progname, argv[i] ? argv[i] : "");
629  usage ();
630  exit (-1);
631  }
632  remote_commands [remote_command_count++] = argv[i];
633  }
634  else if (!strcmp (argv [i], "-raise") ||
635  !strcmp (argv [i], "-noraise"))
636  {
637  char *r = argv [i];
638  if (remote_command_count == remote_command_size)
639  {
640  remote_command_size += 20;
641  remote_commands =
642  (remote_commands
643  ? realloc (remote_commands,
644  remote_command_size * sizeof (char *))
645  : calloc (remote_command_size, sizeof (char *)));
646  }
647  remote_commands [remote_command_count++] = r;
648  }
649  else if (!strcmp (argv [i], "-id"))
650  {
651  char c;
652  if (remote_command_count > 0)
653  {
654  fprintf (stderr,
655  "%s: the `-id' option must preceed all `-remote' options.\n",
656  progname);
657  usage ();
658  exit (-1);
659  }
660  else if (remote_window != 0)
661  {
662  fprintf (stderr, "%s: only one `-id' option may be used.\n",
663  progname);
664  usage ();
665  exit (-1);
666  }
667  i++;
668  if (argv[i] &&
669  1 == sscanf (argv[i], " %ld %c", &remote_window, &c))
670  ;
671  else if (argv[i] &&
672  1 == sscanf (argv[i], " 0x%lx %c", &remote_window, &c))
673  ;
674  else
675  {
676  fprintf (stderr, "%s: invalid `-id' option \"%s\"\n",
677  progname, argv[i] ? argv[i] : "");
678  usage ();
679  exit (-1);
680  }
681  }
682  }
683 
684  dpy = XOpenDisplay (dpy_string);
685  if (! dpy)
686  exit (-1);
687 
688  if (sync_p)
689  XSynchronize (dpy, True);
690 
691  exit (mozilla_remote_commands (dpy, (Window) remote_window,
692  remote_commands));
693 }
694 
695 #endif /* STANDALONE */
usage
static void usage(void)
Definition: arpspoof.c:39
mozilla_remote_init_atoms
static void mozilla_remote_init_atoms(Display *dpy)
Definition: remote.c:68
progname
const char * progname
Definition: webspy.c:35
MOZILLA_COMMAND_PROP
#define MOZILLA_COMMAND_PROP
Definition: remote.c:60
MOZILLA_LOCK_PROP
#define MOZILLA_LOCK_PROP
Definition: remote.c:59
RootWindowOfScreen
#define RootWindowOfScreen(s)
Definition: vroot.h:111
main
int main(int argc, char *argv[])
Definition: arpspoof.c:154
rec::data
struct netobj data
Definition: record.c:37
root
static Window root
Definition: vroot.h:69
expected_mozilla_version
const char * expected_mozilla_version
Definition: webspy.c:34
XA_MOZILLA_VERSION
static Atom XA_MOZILLA_VERSION
Definition: remote.c:62
mozilla_remote_find_window
static Window mozilla_remote_find_window(Display *dpy)
Definition: remote.c:81
MOZILLA_VERSION_PROP
#define MOZILLA_VERSION_PROP
Definition: remote.c:58
mozilla_remote_obtain_lock
static void mozilla_remote_obtain_lock(Display *dpy, Window window)
Definition: remote.c:206
mozilla_remote_commands
int mozilla_remote_commands(Display *dpy, Window window, char **commands)
Definition: remote.c:508
XA_MOZILLA_RESPONSE
static Atom XA_MOZILLA_RESPONSE
Definition: remote.c:65
lock_data
static char * lock_data
Definition: remote.c:203
dpy
Display * dpy
Definition: webspy.c:37
mozilla_remote_check_window
static void mozilla_remote_check_window(Display *dpy, Window window)
Definition: remote.c:174
mozilla_remote_free_lock
static void mozilla_remote_free_lock(Display *dpy, Window window)
Definition: remote.c:303
vroot.h
mozilla_remote_command
static int mozilla_remote_command(Display *dpy, Window window, const char *command, Bool raise_p)
Definition: remote.c:352
XA_MOZILLA_LOCK
static Atom XA_MOZILLA_LOCK
Definition: remote.c:63
XA_MOZILLA_COMMAND
static Atom XA_MOZILLA_COMMAND
Definition: remote.c:64
MOZILLA_RESPONSE_PROP
#define MOZILLA_RESPONSE_PROP
Definition: remote.c:61