File: zenmap_wrapper.py

package info (click to toggle)
nmap 6.47-3%2Bdeb8u2
  • links: PTS, VCS
  • area: main
  • in suites: jessie
  • size: 44,788 kB
  • ctags: 25,108
  • sloc: ansic: 89,741; cpp: 62,412; sh: 19,492; python: 17,323; xml: 11,413; perl: 2,529; makefile: 2,503; yacc: 608; lex: 469; asm: 372; java: 45
file content (174 lines) | stat: -rwxr-xr-x 6,820 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#!/usr/bin/env python

# This is a wrapper script around the zenmap executable, used in a Mac OS X .app
# bundle. It sets environment variables, fills in template configuration files,
# starts X11 if necessary, and execs the real zenmap executable.
#
# This program is the second link in the chain
#     zenmap_auth -> zenmap_wrapper.py -> zenmap.bin

import errno
import os
import os.path
import sys

HOME = os.path.expanduser("~")

def create_dir(path):
    """Create a directory with os.makedirs without raising an error if the
        directory already exists."""
    try:
        os.makedirs(path)
    except OSError, e:
        if e.errno != errno.EEXIST:
            raise

# We will need to rewrite some configuration files to refer to directories
# inside the application bundle, wherever it may be. This is tricky because of
# escaping issues in the formats of the configuration files. The following
# functions handle it.

# The format of pango/pangorc is called "key file." It's described at
# http://library.gnome.org/devel/glib/stable/glib-Key-value-file-parser.

# Escape a string as appropriate for a "key file."
def escape_key_file_value(value):
    result = []
    for c in value:
        if c == "\n":
            c = "\\n"
        elif c == "\t":
            c = "\\t"
        elif c == "\r":
            c = "\\r"
        elif c == "\\":
            c = "\\\\"
        result.append(c)
    if len(result) > 0 and result[0] == " ":
        result[0] = "\\s"
    result = "".join(result)
    return result

def substitute_key_file_line(line, replacements):
    for text, rep in replacements.items():
        line = line.replace(text, escape_key_file_value(rep))
    return line

# Substitute a dict of replacements into a "key file."
def substitute_key_file(in_file_name, out_file_name, replacements):
    in_file = open(in_file_name, "r")
    out_file = open(out_file_name, "w")
    for line in in_file:
        out_file.write(substitute_key_file_line(line, replacements))
    in_file.close()
    out_file.close()

def escape_shell(arg):
    """Escape a string to be a shell argument."""
    result = []
    for c in arg:
        if c in "$`\"\\":
            c = "\\" + c
        result.append(c)
    return "\"" + "".join(result) + "\""

def hack_xinitrc(system_xinitrc_filename, home_xinitrc_filename):
    """Hack the system xinitrc file and put the modified contents into another
    file. The parameter names reflect the fact that this is intended to copy
    the system xinitrc into ~/.xinitrc. The modified xinitrc will delete itself
    on its first invocation and will not run any instances of xterm. This is
    necessary on Mac OS X 10.4 and earlier, which include a call to xterm in
    the system xinitrc."""
    system_xinitrc = open(system_xinitrc_filename, "r")
    home_xinitrc = open(home_xinitrc_filename, "w")
    lines = iter(system_xinitrc)
    # Look for the first non-comment line so we don't preempt the #! line.
    for line in lines:
        if not line.lstrip().startswith("#"):
            break
        home_xinitrc.write(line)
    # Write the self-destruct line.
    home_xinitrc.write("\n")
    home_xinitrc.write("rm -f %s\n" % escape_shell(home_xinitrc_filename))
    home_xinitrc.write(line)
    # Copy the rest, removing any calls to xterm
    for line in lines:
        if line.lstrip().startswith("xterm"):
            line = "# " + line
        home_xinitrc.write(line)
    system_xinitrc.close()
    home_xinitrc.close()

def start_x11():
    """Start the X11 server if necessary and set the DISPLAY environment as
    appropriate. If the user hasn't set up a custom ~/.xinitrc, call
    hack_xinitrc to make a ~/.xinitrc that will not start an xterm along with
    the application. A similar approach is taken by Wireshark and Inkscape."""
    if os.environ.has_key("DISPLAY"):
        return
    system_xinitrc_filename = "/usr/X11R6/lib/X11/xinit/xinitrc"
    home_xinitrc_filename = os.path.join(HOME, ".xinitrc")
    if os.path.exists(system_xinitrc_filename) and not os.path.exists(home_xinitrc_filename):
        hack_xinitrc(system_xinitrc_filename, home_xinitrc_filename)
    os.system("open -a X11")
    os.environ["DISPLAY"] = ":0"

if __name__ == "__main__":
    # Make the real UID equal the effective UID. They are unequal when running
    # with privileges under AuthorizationExecuteWithPrivileges. GTK+ refuses to
    # run if they are different.
    if os.getuid() != os.geteuid():
        os.setuid(os.geteuid())

    # Paths within the application bundle.
    currentdir = os.path.dirname(os.path.abspath(sys.argv[0]))
    parentdir = os.path.dirname(currentdir)
    resourcedir = os.path.join(parentdir, "Resources")

    # A directory where we put automatically generated GTK+ and Pango files.
    # This could be something different like /tmp or "~/Library/Application
    # Support/Zenmap". It is put somewhere other than within the application
    # bundle to allow running from a read-only filesystem.
    etcdir = os.path.join(HOME, ".zenmap-etc")

    # Override the dynamic library search path. This makes the various GTK+ and
    # Pango shared objects look at the bundled copies of the libraries.  py2app
    # puts .dylibs in Contents/Frameworks.
    os.environ["DYLD_LIBRARY_PATH"] = os.path.join(parentdir, "Frameworks")

    # See http://library.gnome.org/devel/gtk/2.12/gtk-running.html for the
    # meaning of the GTK+ environment variables. These files are static and
    # live inside the application bundle.
    os.environ["GTK_DATA_PREFIX"] = resourcedir
    os.environ["GTK_EXE_PREFIX"] = resourcedir
    os.environ["GTK_PATH"] = resourcedir
    os.environ["FONTCONFIG_PATH"] = os.path.join(resourcedir, "etc", "fonts")
    # Use the packaged gtkrc only if the user doesn't have a custom one.
    if not os.path.exists(os.path.expanduser("~/.gtkrc-2.0")):
        os.environ["GTK2_RC_FILES"] = os.path.join(resourcedir, "etc", "gtk-2.0", "gtkrc")

    # The following environment variables refer to files within ~/.zenmap-etc
    # that are automatically generated from templates.
    os.environ["PANGO_RC_FILE"] = os.path.join(etcdir, "pango", "pangorc")

    # Create the template directory.
    create_dir(os.path.join(etcdir, "pango"))

    REPLACEMENTS = {
        "${RESOURCES}": resourcedir,
        "${ETC}": etcdir
    }

    # Fill in the templated configuration files with the correct substitutions.
    KEY_FILE_TEMPLATES = (
        "pango/pangorc",
    )
    for f in KEY_FILE_TEMPLATES:
        in_file_name = os.path.join(resourcedir, "etc", f + ".in")
        out_file_name = os.path.join(etcdir, f)
        substitute_key_file(in_file_name, out_file_name, REPLACEMENTS)

    start_x11()

    # exec the real program.
    os.execl(os.path.join(os.path.dirname(sys.argv[0]), "zenmap.bin"), *sys.argv)