Statistics
| Branch: | Tag: | Revision:

root / vncauthproxy / client.py @ 8b0f290d

History | View | Annotate | Download (7.4 kB)

1 66d17b40 Apollon Oikonomopoulos
#!/usr/bin/env python
2 0c251ab5 Apollon Oikonomopoulos
#
3 7183f55d Faidon Liambotis
# Copyright (c) 2010-2011 Greek Research and Technology Network S.A.
4 0c251ab5 Apollon Oikonomopoulos
#
5 0c251ab5 Apollon Oikonomopoulos
# This program is free software; you can redistribute it and/or modify
6 0c251ab5 Apollon Oikonomopoulos
# it under the terms of the GNU General Public License as published by
7 0c251ab5 Apollon Oikonomopoulos
# the Free Software Foundation; either version 2 of the License, or
8 0c251ab5 Apollon Oikonomopoulos
# (at your option) any later version.
9 0c251ab5 Apollon Oikonomopoulos
#
10 0c251ab5 Apollon Oikonomopoulos
# This program is distributed in the hope that it will be useful, but
11 0c251ab5 Apollon Oikonomopoulos
# WITHOUT ANY WARRANTY; without even the implied warranty of
12 0c251ab5 Apollon Oikonomopoulos
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 0c251ab5 Apollon Oikonomopoulos
# General Public License for more details.
14 0c251ab5 Apollon Oikonomopoulos
#
15 0c251ab5 Apollon Oikonomopoulos
# You should have received a copy of the GNU General Public License
16 0c251ab5 Apollon Oikonomopoulos
# along with this program; if not, write to the Free Software
17 0c251ab5 Apollon Oikonomopoulos
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 0c251ab5 Apollon Oikonomopoulos
# 02110-1301, USA.
19 66d17b40 Apollon Oikonomopoulos
20 66d17b40 Apollon Oikonomopoulos
import sys
21 66d17b40 Apollon Oikonomopoulos
import socket
22 0b74ef50 Stratos Psomadakis
import ssl
23 66d17b40 Apollon Oikonomopoulos
24 48b1400e Vangelis Koukis
try:
25 48b1400e Vangelis Koukis
    import simplejson as json
26 48b1400e Vangelis Koukis
except ImportError:
27 48b1400e Vangelis Koukis
    import json
28 48b1400e Vangelis Koukis
29 b129b0c0 Stratos Psomadakis
try:
30 b129b0c0 Stratos Psomadakis
    from gevent import sleep
31 b129b0c0 Stratos Psomadakis
except ImportError:
32 b129b0c0 Stratos Psomadakis
    import sleep
33 b129b0c0 Stratos Psomadakis
34 b129b0c0 Stratos Psomadakis
DEFAULT_SERVER_ADDRESS = '127.0.0.1'
35 b129b0c0 Stratos Psomadakis
DEFAULT_SERVER_PORT = 24999
36 66d17b40 Apollon Oikonomopoulos
37 31965126 Vangelis Koukis
38 03a592b9 Vangelis Koukis
def parse_arguments(args):
39 03a592b9 Vangelis Koukis
    from optparse import OptionParser
40 03a592b9 Vangelis Koukis
41 03a592b9 Vangelis Koukis
    parser = OptionParser()
42 b129b0c0 Stratos Psomadakis
    parser.add_option("--server", dest="server_address",
43 b129b0c0 Stratos Psomadakis
                      default=DEFAULT_SERVER_ADDRESS,
44 b129b0c0 Stratos Psomadakis
                      metavar="SERVER",
45 cf328b06 Stratos Psomadakis
                      help=("vncauthproxy server address"))
46 b129b0c0 Stratos Psomadakis
    parser.add_option("--server-port", dest="server_port",
47 b129b0c0 Stratos Psomadakis
                      default=DEFAULT_SERVER_PORT, type="int",
48 b129b0c0 Stratos Psomadakis
                      metavar="SERVER_PORT",
49 b129b0c0 Stratos Psomadakis
                      help=("vncauthproxy port"))
50 03a592b9 Vangelis Koukis
    parser.add_option('-s', dest="sport",
51 03a592b9 Vangelis Koukis
                      default=0, type="int",
52 03a592b9 Vangelis Koukis
                      metavar='PORT',
53 03a592b9 Vangelis Koukis
                      help=("Use source port PORT for incoming connections "
54 03a592b9 Vangelis Koukis
                            "(default: allocate a port automatically)"))
55 03a592b9 Vangelis Koukis
    parser.add_option("-d", "--dest",
56 03a592b9 Vangelis Koukis
                      default=None, dest="daddr",
57 03a592b9 Vangelis Koukis
                      metavar="HOST",
58 03a592b9 Vangelis Koukis
                      help="Proxy connection to destination host HOST")
59 03a592b9 Vangelis Koukis
    parser.add_option("-p", "--dport", dest="dport",
60 03a592b9 Vangelis Koukis
                      default=None, type="int",
61 03a592b9 Vangelis Koukis
                      metavar="PORT",
62 03a592b9 Vangelis Koukis
                      help="Proxy connection to destination port PORT")
63 03a592b9 Vangelis Koukis
    parser.add_option("-P", "--password", dest="password",
64 03a592b9 Vangelis Koukis
                      default=None,
65 03a592b9 Vangelis Koukis
                      metavar="PASSWORD",
66 03a592b9 Vangelis Koukis
                      help=("Use password PASSWD to authenticate incoming "
67 03a592b9 Vangelis Koukis
                            "VNC connections"))
68 d49bd2fb Stratos Psomadakis
    parser.add_option("--auth-user", dest="auth_user",
69 d49bd2fb Stratos Psomadakis
                      default=None,
70 d49bd2fb Stratos Psomadakis
                      metavar="AUTH_USER",
71 d49bd2fb Stratos Psomadakis
                      help=("User to authenticate as, for the control "
72 d49bd2fb Stratos Psomadakis
                            "connection"))
73 d49bd2fb Stratos Psomadakis
    parser.add_option("--auth-password", dest="auth_password",
74 d49bd2fb Stratos Psomadakis
                      default=None,
75 d49bd2fb Stratos Psomadakis
                      metavar="AUTH_PASSWORD",
76 d49bd2fb Stratos Psomadakis
                      help=("User password for the control connection "
77 d49bd2fb Stratos Psomadakis
                            "authentication"))
78 d49bd2fb Stratos Psomadakis
    parser.add_option("--no-ssl", dest="no_ssl",
79 6149f03e Stratos Psomadakis
                      action='store_true', default=False,
80 d49bd2fb Stratos Psomadakis
                      help=("Disable SSL/TLS for control connecions "
81 d49bd2fb Stratos Psomadakis
                            "(default: %s)" % False))
82 6149f03e Stratos Psomadakis
    parser.add_option("--ca-cert", dest="ca_cert",
83 6149f03e Stratos Psomadakis
                      default=None,
84 6149f03e Stratos Psomadakis
                      metavar="CACERT",
85 6149f03e Stratos Psomadakis
                      help=("CA certificate file to use for server auth"))
86 6149f03e Stratos Psomadakis
    parser.add_option("--strict", dest="strict",
87 6149f03e Stratos Psomadakis
                      default=False, action='store_true',
88 6149f03e Stratos Psomadakis
                      metavar="STRICT",
89 6149f03e Stratos Psomadakis
                      help=("Perform strict authentication on the server "
90 6149f03e Stratos Psomadakis
                            "SSL cert"))
91 03a592b9 Vangelis Koukis
92 03a592b9 Vangelis Koukis
    (opts, args) = parser.parse_args(args)
93 03a592b9 Vangelis Koukis
94 03a592b9 Vangelis Koukis
    # Mandatory arguments
95 03a592b9 Vangelis Koukis
    if not opts.password:
96 03a592b9 Vangelis Koukis
        parser.error("The -P/--password argument is mandatory.")
97 03a592b9 Vangelis Koukis
    if not opts.daddr:
98 03a592b9 Vangelis Koukis
        parser.error("The -d/--dest argument is mandatory.")
99 03a592b9 Vangelis Koukis
    if not opts.dport:
100 03a592b9 Vangelis Koukis
        parser.error("The -p/--dport argument is mandatory.")
101 d49bd2fb Stratos Psomadakis
    if not opts.auth_user:
102 d49bd2fb Stratos Psomadakis
        parser.error("The --auth-user argument is mandatory.")
103 d49bd2fb Stratos Psomadakis
    if not opts.auth_password:
104 d49bd2fb Stratos Psomadakis
        parser.error("The --auth-password argument is mandatory.")
105 03a592b9 Vangelis Koukis
106 6149f03e Stratos Psomadakis
    # Sanity check
107 6149f03e Stratos Psomadakis
    if opts.strict and not opts.ca_cert:
108 6149f03e Stratos Psomadakis
        parser.error("--strict requires --ca-cert to be set")
109 6149f03e Stratos Psomadakis
    if opts.no_ssl and opts.ca_cert:
110 6149f03e Stratos Psomadakis
        parser.error("--no-ssl and --ca-cert / --strict options "
111 6149f03e Stratos Psomadakis
                     "are mutually exclusive")
112 6149f03e Stratos Psomadakis
113 03a592b9 Vangelis Koukis
    return (opts, args)
114 03a592b9 Vangelis Koukis
115 03a592b9 Vangelis Koukis
116 03a592b9 Vangelis Koukis
def request_forwarding(sport, daddr, dport, password,
117 d49bd2fb Stratos Psomadakis
                       auth_user, auth_password,
118 b129b0c0 Stratos Psomadakis
                       server_address=DEFAULT_SERVER_ADDRESS,
119 6149f03e Stratos Psomadakis
                       server_port=DEFAULT_SERVER_PORT, no_ssl=False,
120 6149f03e Stratos Psomadakis
                       ca_cert=None, strict=False):
121 03a592b9 Vangelis Koukis
    """Connect to vncauthproxy and request a VNC forwarding."""
122 03a592b9 Vangelis Koukis
    if not password:
123 03a592b9 Vangelis Koukis
        raise ValueError("You must specify a non-empty password")
124 03a592b9 Vangelis Koukis
125 48b1400e Vangelis Koukis
    req = {
126 48b1400e Vangelis Koukis
        "source_port": int(sport),
127 48b1400e Vangelis Koukis
        "destination_address": daddr,
128 48b1400e Vangelis Koukis
        "destination_port": int(dport),
129 b129b0c0 Stratos Psomadakis
        "password": password,
130 d49bd2fb Stratos Psomadakis
        "auth_user": auth_user,
131 d49bd2fb Stratos Psomadakis
        "auth_password": auth_password,
132 48b1400e Vangelis Koukis
    }
133 66d17b40 Apollon Oikonomopoulos
134 8b0f290d Stratos Psomadakis
    last_error = None
135 b129b0c0 Stratos Psomadakis
    retries = 5
136 b129b0c0 Stratos Psomadakis
    while retries:
137 b129b0c0 Stratos Psomadakis
        # Initiate server connection
138 b129b0c0 Stratos Psomadakis
        for res in socket.getaddrinfo(server_address, server_port,
139 b129b0c0 Stratos Psomadakis
                                      socket.AF_UNSPEC,
140 b129b0c0 Stratos Psomadakis
                                      socket.SOCK_STREAM, 0,
141 b129b0c0 Stratos Psomadakis
                                      socket.AI_PASSIVE):
142 b129b0c0 Stratos Psomadakis
            af, socktype, proto, canonname, sa = res
143 b129b0c0 Stratos Psomadakis
            try:
144 b129b0c0 Stratos Psomadakis
                server = socket.socket(af, socktype, proto)
145 b129b0c0 Stratos Psomadakis
            except socket.error:
146 b129b0c0 Stratos Psomadakis
                server = None
147 b129b0c0 Stratos Psomadakis
                continue
148 b129b0c0 Stratos Psomadakis
149 d49bd2fb Stratos Psomadakis
            if not no_ssl:
150 6149f03e Stratos Psomadakis
                reqs = ssl.CERT_NONE
151 6149f03e Stratos Psomadakis
                if strict:
152 6149f03e Stratos Psomadakis
                    reqs = ssl.CERT_REQUIRED
153 6149f03e Stratos Psomadakis
                elif ca_cert:
154 6149f03e Stratos Psomadakis
                    reqs = ssl.CERT_OPTIONAL
155 6149f03e Stratos Psomadakis
156 0b74ef50 Stratos Psomadakis
                server = ssl.wrap_socket(
157 6149f03e Stratos Psomadakis
                      server, cert_reqs=reqs, ca_certs=ca_cert,
158 0b74ef50 Stratos Psomadakis
                      ssl_version=ssl.PROTOCOL_TLSv1)
159 0b74ef50 Stratos Psomadakis
160 b129b0c0 Stratos Psomadakis
            server.settimeout(60.0)
161 b129b0c0 Stratos Psomadakis
162 b129b0c0 Stratos Psomadakis
            try:
163 b129b0c0 Stratos Psomadakis
                server.connect(sa)
164 8b0f290d Stratos Psomadakis
            except socket.error as err:
165 b129b0c0 Stratos Psomadakis
                server.close()
166 b129b0c0 Stratos Psomadakis
                server = None
167 d49bd2fb Stratos Psomadakis
                retries -= 1
168 8b0f290d Stratos Psomadakis
                last_error = err
169 b129b0c0 Stratos Psomadakis
                continue
170 b129b0c0 Stratos Psomadakis
171 b129b0c0 Stratos Psomadakis
            retries = 0
172 b129b0c0 Stratos Psomadakis
            break
173 b129b0c0 Stratos Psomadakis
174 b129b0c0 Stratos Psomadakis
        sleep(0.2)
175 b129b0c0 Stratos Psomadakis
176 b129b0c0 Stratos Psomadakis
    if server is None:
177 8b0f290d Stratos Psomadakis
        raise Exception("Failed to connect to server: %s" % last_error)
178 b129b0c0 Stratos Psomadakis
179 b129b0c0 Stratos Psomadakis
    server.send(json.dumps(req))
180 b129b0c0 Stratos Psomadakis
181 b129b0c0 Stratos Psomadakis
    response = server.recv(1024)
182 b129b0c0 Stratos Psomadakis
    server.close()
183 48b1400e Vangelis Koukis
    res = json.loads(response)
184 48b1400e Vangelis Koukis
    return res
185 66d17b40 Apollon Oikonomopoulos
186 03a592b9 Vangelis Koukis
187 66d17b40 Apollon Oikonomopoulos
if __name__ == '__main__':
188 03a592b9 Vangelis Koukis
    (opts, args) = parse_arguments(sys.argv[1:])
189 03a592b9 Vangelis Koukis
190 03a592b9 Vangelis Koukis
    res = request_forwarding(sport=opts.sport, daddr=opts.daddr,
191 d49bd2fb Stratos Psomadakis
                             dport=opts.dport, password=opts.password,
192 d49bd2fb Stratos Psomadakis
                             auth_user=opts.auth_user,
193 d49bd2fb Stratos Psomadakis
                             auth_password=opts.auth_password,
194 6149f03e Stratos Psomadakis
                             no_ssl=opts.no_ssl, ca_cert=opts.ca_cert,
195 6149f03e Stratos Psomadakis
                             strict=opts.strict)
196 d49bd2fb Stratos Psomadakis
197 d49bd2fb Stratos Psomadakis
    reason = None
198 d49bd2fb Stratos Psomadakis
    if 'reason' in res:
199 d49bd2fb Stratos Psomadakis
        reason = 'Reason: %s\n' % res['reason']
200 d49bd2fb Stratos Psomadakis
    sys.stderr.write("Forwaring %s -> %s:%s: %s\n%s" % (res['source_port'],
201 03a592b9 Vangelis Koukis
                                                      opts.daddr, opts.dport,
202 d49bd2fb Stratos Psomadakis
                                                      res['status'], reason))
203 03a592b9 Vangelis Koukis
204 48b1400e Vangelis Koukis
    if res['status'] == "OK":
205 48b1400e Vangelis Koukis
        sys.exit(0)
206 48b1400e Vangelis Koukis
    else:
207 48b1400e Vangelis Koukis
        sys.exit(1)