Revision 3b98303f
b/Changelog | ||
---|---|---|
13 | 13 |
* Add Changelog, README and docs |
14 | 14 |
* Replace Unix domain control sockets with TCP control sockets, with |
15 | 15 |
basic authentication and SSL support. |
16 |
* Add the vncauthproxy-passwd tool to manage the users file. |
b/MANIFEST.in | ||
---|---|---|
3 | 3 |
|
4 | 4 |
recursive-include vncauthproxy * |
5 | 5 |
recursive-include docs * |
6 |
recursive-include examples * |
b/docs/index.rst | ||
---|---|---|
18 | 18 |
* IPv4 and IPv6 support |
19 | 19 |
* Configurable timeout for client connections |
20 | 20 |
|
21 |
Its main use is to enable VNC clients to connect to firwalled VNC servers. |
|
21 |
Its main use is to enable VNC clients to connect to firewalled VNC servers.
|
|
22 | 22 |
|
23 | 23 |
It is used by `Synnefo <https://code.grnet.gr/projects/synnefo>`_ to provide |
24 | 24 |
users with (VNC) console access to their VMs. |
... | ... | |
26 | 26 |
Installation |
27 | 27 |
^^^^^^^^^^^^ |
28 | 28 |
|
29 |
snf-vncauthproxy is currently packaged only for Debian (stable / oldstable).
|
|
29 |
snf-vncauthproxy is currently packaged only for Debian (stable). |
|
30 | 30 |
|
31 | 31 |
You can find and install the latest version snf-vncauthproxy at Synnefo's apt |
32 | 32 |
repository: |
... | ... | |
37 | 37 |
|
38 | 38 |
| ``curl https://dev.grnet.gr/files/apt-grnetdev.pub | apt-key add -`` |
39 | 39 |
|
40 |
In case you're upgrading from an older snf-vncauthproxy version or it's the |
|
41 |
first time you're installing snf-vncauthproxy, you will prompted to configure |
|
42 |
a vncauthproxy user (see below for more information on user management). |
|
43 |
|
|
40 | 44 |
Overview |
41 | 45 |
^^^^^^^^ |
42 | 46 |
|
43 |
snf-vncauthproxy listens on a TCP socket for control (JSON) messages from clients.
|
|
44 |
The format of the control messages is: |
|
47 |
snf-vncauthproxy listens on a TCP socket for control (JSON) messages from |
|
48 |
clients. The format of the control messages is:
|
|
45 | 49 |
|
46 | 50 |
.. code-block:: console |
47 | 51 |
|
... | ... | |
89 | 93 |
The snf-vncauthproxy daemon can be either run manually or managed via its init |
90 | 94 |
script. |
91 | 95 |
|
92 |
If you're using the init script, snf-vncauthproxy reads its paramater from its
|
|
96 |
If you're using the init script, snf-vncauthproxy reads its options from its
|
|
93 | 97 |
default file (``DAEMON_OPTS`` parameter in ``/etc/default/vncauthproxy``). |
98 |
Refer to the vncauthproxy help output for a detailed listing and information |
|
99 |
on all available options: |
|
100 |
|
|
101 |
.. code-block:: console |
|
94 | 102 |
|
95 |
By default snf-vncauthproxy will listen to ``127.0.0.1:24999`` TCP, for incoming |
|
96 |
control connections and uses the ``25000-30000`` range for the listening / data |
|
97 |
sockets. |
|
103 |
# vncauthproxy --help |
|
98 | 104 |
|
99 |
Version 1.5 introduced replaced Unix domain control sockets with TCP |
|
100 |
control sockets. This change made it necessary to also introduce an |
|
101 |
authentication file to replace the Unix file permissions, which protected the |
|
102 |
domain sockets. |
|
105 |
By default snf-vncauthproxy will listen to ``127.0.0.1:24999`` TCP, for |
|
106 |
incoming control connections and uses the ``25000-30000`` range for the |
|
107 |
listening / data sockets. |
|
108 |
|
|
109 |
Version 1.5 replaced Unix domain control sockets with TCP control sockets. This |
|
110 |
change made it necessary to introduce an authentication file to replace the |
|
111 |
POSIX file permissions, which protected the domain sockets. |
|
103 | 112 |
|
104 | 113 |
The default path for the auth file is ``/var/lib/vncauthproxy/users`` |
105 | 114 |
(configurable by the ``--auth-file`` option). Each line in the file represents |
... | ... | |
108 | 117 |
|
109 | 118 |
.. code-block:: console |
110 | 119 |
|
111 |
user password |
|
112 |
user1 {cleartext}password |
|
113 |
user2 {HA1}md5hash |
|
120 |
username:$6$salt$hash |
|
121 |
|
|
122 |
The password part of the line (after the colon) is the output of crypt(), using |
|
123 |
a random 16-char salt with SHA-512. |
|
124 |
|
|
125 |
To manage the authentication file, you can use the vncauthproxy-passwd tool, |
|
126 |
to easily add, update and delete users: |
|
127 |
|
|
128 |
To add a user: |
|
129 |
|
|
130 |
.. code-block:: console |
|
131 |
|
|
132 |
# vncauthproxy-passwd /var/lib/vncauthproxy/users user |
|
133 |
|
|
134 |
You will be prompted for a password. |
|
114 | 135 |
|
115 |
The Debian package provides an example users file. |
|
136 |
To delete a user: |
|
137 |
|
|
138 |
.. code-block:: console |
|
139 |
|
|
140 |
# vncauthproxy-passwd -D /var/lib/vncauthproxy/users user |
|
141 |
|
|
142 |
See the help output of the tool for more options: |
|
143 |
|
|
144 |
.. code-block:: console |
|
145 |
|
|
146 |
# vncauthproxy-passwd -h |
|
147 |
|
|
148 |
.. warning:: The vncauthproxy daemon requires a restart for the changes in the |
|
149 |
authentication file to take effect. |
|
150 |
|
|
151 |
.. warning:: After installing snf-vncauthproxy for the fist time, make sure |
|
152 |
that you create a valid authentication file and define any users needed. The |
|
153 |
vncauthproxy daemon will start but will not be usable if no users are defined |
|
154 |
or if no authentication file is present. |
|
116 | 155 |
|
117 | 156 |
Version 1.5 introduced also support for SSL for the control socket. If you |
118 | 157 |
enable SSL support (``--enable-ssl`` parameter, disabled by default) you wil |
... | ... | |
161 | 200 |
snf-cyclades-app can connect to the snf-vncauthproxy on the listening address / |
162 | 201 |
port. It's also recommended to enable SSL on the control socket in that case. |
163 | 202 |
|
164 |
.. include:: changelog.rst |
|
203 |
Changelog |
|
204 |
^^^^^^^^^ |
|
205 |
|
|
206 |
* v1.5 :ref:`Changelog <Changelog-1.5>` |
|
207 |
|
|
208 |
Upgrade notes |
|
209 |
^^^^^^^^^^^^^ |
|
210 |
|
|
211 |
.. toctree:: |
|
212 |
:maxdepth: 1 |
|
165 | 213 |
|
166 |
.. include:: upgrade.rst
|
|
214 |
v1.4 -> v1.5 <upgrade/upgrade-1.5.rst>
|
|
167 | 215 |
|
168 | 216 |
Contact |
169 | 217 |
^^^^^^^ |
/dev/null | ||
---|---|---|
1 |
Upgrade notes |
|
2 |
^^^^^^^^^^^^^ |
|
3 |
|
|
4 |
v1.5 |
|
5 |
==== |
|
6 |
Version 1.5 replaced Unix domain control sockets with TCP |
|
7 |
control sockets. This change made it necessary to also introduce an |
|
8 |
authentication file to replace the POSIX file permissions, which protected the |
|
9 |
domain sockets. |
|
10 |
|
|
11 |
The default path for the auth file is ``/var/lib/vncauthproxy/users`` |
|
12 |
(configurable by the ``--auth-file`` option). Each line in the file represents |
|
13 |
one user which is allowed to use the control socket and should be in the |
|
14 |
following format: |
|
15 |
|
|
16 |
.. code-block:: console |
|
17 |
|
|
18 |
user password |
|
19 |
user1 {cleartext}password |
|
20 |
user2 {HA1}md5hash |
|
21 |
|
|
22 |
If you want to use a hash instead of a password, you should provide the MD5 |
|
23 |
digest of the string ``user:vncauthproxy:password``. It can be generated with |
|
24 |
the following command: |
|
25 |
|
|
26 |
.. code-block:: console |
|
27 |
|
|
28 |
$ echo -n 'user:vncauthproxy:password' | openssl md5 |
|
29 |
|
|
30 |
The Debian package provides an example users file. |
|
31 |
|
|
32 |
Version 1.5 also introduced support for SSL for the control socket. If you |
|
33 |
enable SSL support (``--enable-ssl`` parameter, disabled by default) you will |
|
34 |
have to provide a certficate and key file (``--cert-file`` and ``--key-file`` |
|
35 |
parameters). The default values for certificate and key files are |
|
36 |
``/var/lib/vncauthrpoxy/{cert,key}.pem`` respectively. |
|
37 |
|
|
38 |
If you're using snf-vncauthproxy with Synnefo, you should make sure to edit the |
|
39 |
``CYCLADES_VNCAUTHPROXY_OPTS`` setting in |
|
40 |
``/etc/synnefo/20-snf-cyclades-app-api.conf``. The |
|
41 |
``CYCLADES_VNCAUTHPROXY_OPTS`` dict in |
|
42 |
``/etc/synnefo/20-snf-cyclades-app-api.conf`` should be edited to match |
|
43 |
snf-vncauthproxy configuration (user, password, SSL support, certificate file). |
|
44 |
You should also make sure that the node running snf-cyclades-app can connect to |
|
45 |
the snf-vncauthproxy's control socket address / port (the suggested deployment to |
|
46 |
run snf-vncauthproxy on the same host as snf-cyclades-app should work with |
|
47 |
the defaults of snf-vncauthproxy, with the exception of the authentication |
|
48 |
file). |
b/docs/upgrade/upgrade-1.5.rst | ||
---|---|---|
1 |
Upgrade notes |
|
2 |
^^^^^^^^^^^^^ |
|
3 |
|
|
4 |
v1.5 |
|
5 |
==== |
|
6 |
Version 1.5 replaced Unix domain control sockets with TCP control sockets. This |
|
7 |
change made it necessary to introduce an authentication file to replace the |
|
8 |
POSIX file permissions, which protected the domain sockets. |
|
9 |
|
|
10 |
You can configure vncauthproxy daemon by modifying the Debian default file |
|
11 |
(``/etc/default/vncauthproxy``) and more specifically the ``DAEMON_OPTS`` |
|
12 |
variable. This option (along with the modified ``CHUID`` option) has been added |
|
13 |
to the v1.5 default file (which you'll need to 'merge' if you're upgrading from |
|
14 |
an older version of snf-vncauthproxy). |
|
15 |
|
|
16 |
The ``DAEMON_OPTS`` variable accepts any valid option you can pass to the |
|
17 |
vncauthproxy daemon on the command line. For a detailed listing and information |
|
18 |
about the avaialble options plese check vncauthproxy help output: |
|
19 |
|
|
20 |
.. code-block:: console |
|
21 |
|
|
22 |
# vncauthproxy --help |
|
23 |
|
|
24 |
The default path for the auth file is ``/var/lib/vncauthproxy/users`` |
|
25 |
(configurable by the ``--auth-file`` option). Each line in the file represents |
|
26 |
one user which is allowed to use the control socket and should be in the |
|
27 |
following format: |
|
28 |
|
|
29 |
.. code-block:: console |
|
30 |
|
|
31 |
username:$6$salt$hash |
|
32 |
|
|
33 |
The password part of the line (after the colon) is the output of crypt(), using |
|
34 |
a random 16-char salt with SHA-512. |
|
35 |
|
|
36 |
To manage the authentication file, you can use the vncauthproxy-passwd tool, |
|
37 |
to easily add, update and delete users: |
|
38 |
|
|
39 |
To add a user: |
|
40 |
|
|
41 |
.. code-block:: console |
|
42 |
|
|
43 |
# vncauthproxy-passwd /var/lib/vncauthproxy/users user |
|
44 |
|
|
45 |
You will be prompted for a password. |
|
46 |
|
|
47 |
To delete a user: |
|
48 |
|
|
49 |
.. code-block:: console |
|
50 |
|
|
51 |
# vncauthproxy-passwd -D /var/lib/vncauthproxy/users user |
|
52 |
|
|
53 |
See the help output of the tool for more options: |
|
54 |
|
|
55 |
.. code-block:: console |
|
56 |
|
|
57 |
# vncauthproxy-passwd -h |
|
58 |
|
|
59 |
.. warning:: The vncauthproxy daemon requires a restart for the changes in the |
|
60 |
authentication file to take effect. |
|
61 |
|
|
62 |
.. warning:: After installing snf-vncauthproxy for the fist time, make sure |
|
63 |
that you create a valid authentication file and define any users needed. The |
|
64 |
vncauthproxy daemon will start but will not be usable if no users are defined |
|
65 |
or if no authentication file is present. |
|
66 |
|
|
67 |
Version 1.5 also introduced support for SSL for the control socket. If you |
|
68 |
enable SSL support (``--enable-ssl`` parameter, disabled by default) you will |
|
69 |
have to provide a certficate and key file (``--cert-file`` and ``--key-file`` |
|
70 |
parameters). The default values for certificate and key files are |
|
71 |
``/var/lib/vncauthrpoxy/{cert,key}.pem`` respectively. |
|
72 |
|
|
73 |
If you're using snf-vncauthproxy with Synnefo, you should make sure to edit the |
|
74 |
``CYCLADES_VNCAUTHPROXY_OPTS`` setting in |
|
75 |
``/etc/synnefo/20-snf-cyclades-app-api.conf``. The |
|
76 |
``CYCLADES_VNCAUTHPROXY_OPTS`` dict in |
|
77 |
``/etc/synnefo/20-snf-cyclades-app-api.conf`` should be edited to match |
|
78 |
snf-vncauthproxy configuration (user, password, SSL support, certificate file). |
|
79 |
You should also make sure that the node running snf-cyclades-app can connect to |
|
80 |
the snf-vncauthproxy's control socket address / port (the suggested deployment to |
|
81 |
run snf-vncauthproxy on the same host as snf-cyclades-app should work with |
|
82 |
the defaults of snf-vncauthproxy, with the exception of the authentication |
|
83 |
file). |
|
84 |
|
|
85 |
Finally, snf-vncauthproxy now adds a user and group (``vncauthproxy``) to be |
|
86 |
used by the vncauthproxy daemon. As a result the ``CHUID`` option in the Debian |
|
87 |
default file (``/etc/default/vncauthproxy``) has changed accordingly. Although |
|
88 |
it is recommended to run vncauhtproxy with the predfined user and group, it's |
|
89 |
not mandatory. |
/dev/null | ||
---|---|---|
1 |
user password |
|
2 |
user1 {cleartext}password |
|
3 |
user2 {HA1}md5hash |
b/setup.py | ||
---|---|---|
40 | 40 |
], |
41 | 41 |
entry_points={ |
42 | 42 |
'console_scripts': [ |
43 |
'vncauthproxy = vncauthproxy.proxy:main' |
|
43 |
'vncauthproxy = vncauthproxy.proxy:main', |
|
44 |
'vncauthproxy-passwd = vncauthproxy.passwd:main' |
|
44 | 45 |
] |
45 | 46 |
} |
46 | 47 |
) |
b/vncauthproxy/client.py | ||
---|---|---|
59 | 59 |
help=("Use source port PORT for incoming connections " |
60 | 60 |
"(default: allocate a port automatically)")) |
61 | 61 |
parser.add_option("-d", "--dest", |
62 |
default=None, dest="daddr",
|
|
62 |
dest="daddr", |
|
63 | 63 |
metavar="HOST", |
64 | 64 |
help="Proxy connection to destination host HOST") |
65 | 65 |
parser.add_option("-p", "--dport", dest="dport", |
66 |
default=None, type="int",
|
|
66 |
type="int", |
|
67 | 67 |
metavar="PORT", |
68 | 68 |
help="Proxy connection to destination port PORT") |
69 | 69 |
parser.add_option("-P", "--password", dest="password", |
70 |
default=None, |
|
71 | 70 |
metavar="PASSWORD", |
72 | 71 |
help=("Use password PASSWD to authenticate incoming " |
73 | 72 |
"VNC connections")) |
74 | 73 |
parser.add_option("--auth-user", dest="auth_user", |
75 |
default=None, |
|
76 | 74 |
metavar="AUTH_USER", |
77 | 75 |
help=("User to authenticate as, for the control " |
78 | 76 |
"connection")) |
79 | 77 |
parser.add_option("--auth-password", dest="auth_password", |
80 |
default=None, |
|
81 | 78 |
metavar="AUTH_PASSWORD", |
82 | 79 |
help=("User password for the control connection " |
83 | 80 |
"authentication")) |
... | ... | |
105 | 102 |
server_address=DEFAULT_SERVER_ADDRESS, |
106 | 103 |
server_port=DEFAULT_SERVER_PORT, enable_ssl=False, |
107 | 104 |
ca_cert=None, strict=False): |
108 |
"""Connect to vncauthproxy and request a VNC forwarding.""" |
|
109 |
|
|
110 |
# Mandatory arguments |
|
111 |
if not password: |
|
112 |
raise Exception("The password argument is mandatory.") |
|
113 |
if not daddr: |
|
114 |
raise Exception("The daddr argument is mandatory.") |
|
115 |
if not dport: |
|
116 |
raise Exception("The dport argument is mandatory.") |
|
117 |
if not auth_user: |
|
118 |
raise Exception("The auth_user argument is mandatory.") |
|
119 |
if not auth_password: |
|
120 |
raise Exception("The auth_password argument is mandatory.") |
|
105 |
""" Connect to vncauthproxy and request a VNC forwarding. |
|
106 |
|
|
107 |
@type sport: int |
|
108 |
@param sport: Source port for incoming connections |
|
109 |
(0 for automatic allocation)" |
|
110 |
@type daddr: str |
|
111 |
@param daddr: Destination address for the forwarding |
|
112 |
@type dport: int |
|
113 |
@param dport: Destination port for the forwarding |
|
114 |
@type password: str |
|
115 |
@param password: VNC server auth password |
|
116 |
@type auth_user: str |
|
117 |
@param auth_user: vncauthproxy user |
|
118 |
@type auth_password: str |
|
119 |
@param auth_password: vncauthproxy password |
|
120 |
@type server_address: str |
|
121 |
@param server_address: Listening address for the vncauthproxy daemon |
|
122 |
(default: 127.0.0.1) |
|
123 |
@type server_port: int |
|
124 |
@param server_port: Listening port for the vncauthproxy daemon |
|
125 |
(default: 24999) |
|
126 |
@type enable_ssl: bool |
|
127 |
@param enable_ssl: Enable / disable SSL on the control socket |
|
128 |
@type ca_cert: str |
|
129 |
@param ca_cert: Path to the CA cert file |
|
130 |
@type strict: bool |
|
131 |
@param strict: Enable strict cert checking for SSL |
|
132 |
@rtype: dict |
|
133 |
@return: Server response in dict / JSON format |
|
134 |
|
|
135 |
""" |
|
121 | 136 |
|
122 | 137 |
# Sanity check |
123 | 138 |
if strict and not ca_cert: |
124 | 139 |
raise Exception("strict requires ca-cert to be set") |
125 | 140 |
if not enable_ssl and (strict or ca_cert): |
126 |
logger.warning("strict or ca_cert set, but ssl not enabled")
|
|
141 |
logger.warning("strict or ca-cert set, but ssl not enabled")
|
|
127 | 142 |
|
128 | 143 |
req = { |
129 | 144 |
"source_port": int(sport), |
... | ... | |
192 | 207 |
|
193 | 208 |
(opts, args) = parse_arguments(sys.argv[1:]) |
194 | 209 |
|
210 |
# Mandatory arguments |
|
211 |
if opts.password is None: |
|
212 |
sys.stderr.write("The password argument is mandatory.\n") |
|
213 |
sys.exit(1) |
|
214 |
if opts.daddr is None: |
|
215 |
sys.stderr.write("The daddr argument is mandatory.\n") |
|
216 |
if opts.dport is None: |
|
217 |
sys.stderr.write("The dport argument is mandatory.\n") |
|
218 |
if opts.auth_user is None: |
|
219 |
sys.stderr.write("The auth_user argument is mandatory.\n") |
|
220 |
if opts.auth_password is None: |
|
221 |
sys.stderr.write("The auth_password argument is mandatory.\n") |
|
222 |
|
|
195 | 223 |
res = request_forwarding(sport=opts.sport, daddr=opts.daddr, |
196 | 224 |
dport=opts.dport, password=opts.password, |
197 | 225 |
auth_user=opts.auth_user, |
b/vncauthproxy/passwd.py | ||
---|---|---|
1 |
#!/usr/bin/env python |
|
2 |
""" |
|
3 |
vncauthproxy-passwd - vncauthproxy passwd file mgmt tool |
|
4 |
""" |
|
5 |
# |
|
6 |
# Copyright (c) 2010-2013 Greek Research and Technology Network S.A. |
|
7 |
# |
|
8 |
# This program is free software; you can redistribute it and/or modify |
|
9 |
# it under the terms of the GNU General Public License as published by |
|
10 |
# the Free Software Foundation; either version 2 of the License, or |
|
11 |
# (at your option) any later version. |
|
12 |
# |
|
13 |
# This program is distributed in the hope that it will be useful, but |
|
14 |
# WITHOUT ANY WARRANTY; without even the implied warranty of |
|
15 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
16 |
# General Public License for more details. |
|
17 |
# |
|
18 |
# You should have received a copy of the GNU General Public License |
|
19 |
# along with this program; if not, write to the Free Software |
|
20 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
|
21 |
# 02110-1301, USA. |
|
22 |
|
|
23 |
import argparse |
|
24 |
import crypt |
|
25 |
import getpass |
|
26 |
import os |
|
27 |
import random |
|
28 |
import re |
|
29 |
import string |
|
30 |
import sys |
|
31 |
import tempfile |
|
32 |
|
|
33 |
|
|
34 |
def parse_arguments(): |
|
35 |
""" Parse cli args. """ |
|
36 |
parser = argparse.ArgumentParser() |
|
37 |
|
|
38 |
parser.add_argument("-n", "--dry-run", action="store_true", dest="dry_run", |
|
39 |
help="Display the results on stdout without updating " |
|
40 |
"the passwd file") |
|
41 |
parser.add_argument("-D", "--delete", action="store_true", |
|
42 |
dest="delete_user", help="Delete user from file") |
|
43 |
parser.add_argument("passwdfile", metavar="file", type=str, nargs=1, |
|
44 |
help="Path to the passwd file") |
|
45 |
parser.add_argument("user", metavar="user", type=str, nargs=1, |
|
46 |
help="User to edit") |
|
47 |
|
|
48 |
args = parser.parse_args() |
|
49 |
|
|
50 |
return args |
|
51 |
|
|
52 |
|
|
53 |
def gen_salt(): |
|
54 |
""" Generate 16-char salt string. """ |
|
55 |
chars = list(string.ascii_letters + string.digits + "./") |
|
56 |
random.shuffle(chars) |
|
57 |
|
|
58 |
return "".join(random.choice(chars) for x in range(16)) |
|
59 |
|
|
60 |
|
|
61 |
def gen_hash(username, password): |
|
62 |
""" Generate SHA-512 hash in crypt() format. """ |
|
63 |
salt = "$6$%s$" % gen_salt() |
|
64 |
return "%s:%s\n" % (username, crypt.crypt(password, salt)) |
|
65 |
|
|
66 |
|
|
67 |
def fail(reason): |
|
68 |
""" Print reason for failure and exit. """ |
|
69 |
sys.stderr.write("%s\n" % reason) |
|
70 |
sys.exit(1) |
|
71 |
|
|
72 |
|
|
73 |
def find_user(lines, user): |
|
74 |
""" Return user info from passwd file, if the users exists. """ |
|
75 |
for (idx, line) in enumerate(lines): |
|
76 |
(username, _) = line.split(":", 1) |
|
77 |
if user == username: |
|
78 |
return (idx, line) |
|
79 |
|
|
80 |
return None |
|
81 |
|
|
82 |
|
|
83 |
def write_wrapper(passwdfile, lines, dry_run): |
|
84 |
""" Dry-run wrapper for write. """ |
|
85 |
if not dry_run: |
|
86 |
(fd, name) = tempfile.mkstemp() |
|
87 |
with os.fdopen(fd, "w+") as f: |
|
88 |
f.write("".join(lines)) |
|
89 |
os.rename(name, passwdfile) |
|
90 |
else: |
|
91 |
sys.stderr.write("".join(lines)) |
|
92 |
|
|
93 |
|
|
94 |
def delete_user(user, passwdfile): |
|
95 |
""" Delete user from passwdfile. """ |
|
96 |
if not os.path.isfile(passwdfile): |
|
97 |
fail("Cannot delete user from non-existent file") |
|
98 |
|
|
99 |
lines = open(passwdfile).readlines() |
|
100 |
user_line = find_user(lines, user) |
|
101 |
if not user_line: |
|
102 |
fail("User not found!") |
|
103 |
|
|
104 |
(idx, line) = user_line |
|
105 |
lines.remove(line) |
|
106 |
return lines |
|
107 |
|
|
108 |
|
|
109 |
def add_or_update_user(user, passwdfile): |
|
110 |
""" Add or update user from passwdfile. """ |
|
111 |
password = getpass.getpass() |
|
112 |
if password == "": |
|
113 |
fail("Password cannot be empty") |
|
114 |
|
|
115 |
if password != getpass.getpass("Retype password: "): |
|
116 |
fail("Passwords don't match") |
|
117 |
|
|
118 |
newline = gen_hash(user, password) |
|
119 |
|
|
120 |
lines = [newline] |
|
121 |
if os.path.isfile(passwdfile): |
|
122 |
lines = open(passwdfile).readlines() |
|
123 |
user_line = find_user(lines, user) |
|
124 |
if not user_line: |
|
125 |
lines.append(newline) |
|
126 |
else: |
|
127 |
(idx, _) = user_line |
|
128 |
lines[idx] = newline |
|
129 |
|
|
130 |
return lines |
|
131 |
|
|
132 |
|
|
133 |
def main(): |
|
134 |
""" Run the tool from the command line. """ |
|
135 |
try: |
|
136 |
args = parse_arguments() |
|
137 |
|
|
138 |
user = args.user[0] |
|
139 |
passwdfile = args.passwdfile[0] |
|
140 |
|
|
141 |
user_re = r'^[a-z_][a-z0-9_]{0,30}$' |
|
142 |
if re.match(user_re, user) is None: |
|
143 |
fail("Username must match the following regexp: %s" % user_re) |
|
144 |
|
|
145 |
if args.delete_user: |
|
146 |
lines = delete_user(user, passwdfile) |
|
147 |
else: |
|
148 |
lines = add_or_update_user(user, passwdfile) |
|
149 |
|
|
150 |
write_wrapper(passwdfile, lines, args.dry_run) |
|
151 |
except KeyboardInterrupt: |
|
152 |
pass |
|
153 |
|
|
154 |
sys.exit(0) |
b/vncauthproxy/proxy.py | ||
---|---|---|
70 | 70 |
import daemon |
71 | 71 |
import random |
72 | 72 |
import daemon.runner |
73 |
import hashlib |
|
74 |
import re |
|
73 |
import crypt |
|
75 | 74 |
|
76 | 75 |
from vncauthproxy import rfb |
77 | 76 |
|
... | ... | |
345 | 344 |
self.password = req['password'] |
346 | 345 |
|
347 | 346 |
if auth_user not in VncAuthProxy.authdb: |
348 |
msg = "Authentication failure: user not found"
|
|
347 |
msg = "vncauthproxy authentication failure: user not found"
|
|
349 | 348 |
raise InternalError(msg) |
350 | 349 |
|
351 |
(cipher, authdb_password) = VncAuthProxy.authdb[auth_user]
|
|
352 |
if cipher == 'HA1':
|
|
353 |
message = auth_user + ':vncauthproxy:' + auth_password
|
|
354 |
auth_password = hashlib.md5(message).hexdigest()
|
|
350 |
(cipher, salt, authdb_hash) = VncAuthProxy.authdb[auth_user]
|
|
351 |
crypt_result = crypt.crypt(auth_password, '$%s$%s$' %
|
|
352 |
(cipher, salt))
|
|
353 |
passhash = crypt_result.lstrip('$').split('$', 2)[-1]
|
|
355 | 354 |
|
356 |
if auth_password != authdb_password:
|
|
357 |
msg = "Authentication failure: wrong password"
|
|
355 |
if passhash != authdb_hash:
|
|
356 |
msg = "vncauthproxy authentication failure: wrong password"
|
|
358 | 357 |
raise InternalError(msg) |
359 | 358 |
except KeyError: |
360 | 359 |
msg = "Malformed request: %s" % buf |
... | ... | |
618 | 617 |
|
619 | 618 |
|
620 | 619 |
def parse_auth_file(auth_file): |
621 |
supported_ciphers = ('cleartext', 'HA1', None) |
|
622 |
regexp = re.compile(r'^\s*(?P<user>\S+)\s+({(?P<cipher>\S+)})?' |
|
623 |
r'(?P<pass>\S+)\s*$') |
|
624 |
|
|
625 | 620 |
users = {} |
626 | 621 |
|
627 | 622 |
if os.path.isfile(auth_file) is False: |
... | ... | |
631 | 626 |
|
632 | 627 |
try: |
633 | 628 |
with open(auth_file) as f: |
634 |
lines = [l.strip() for l in f.readlines()] |
|
635 |
|
|
636 |
for line in lines: |
|
637 |
if not line or line.startswith('#'): |
|
638 |
continue |
|
639 |
|
|
640 |
m = regexp.match(line) |
|
641 |
if not m: |
|
642 |
raise InternalError("Invaild entry in auth file: %s" |
|
643 |
% line) |
|
644 |
|
|
645 |
user = m.group('user') |
|
646 |
cipher = m.group('cipher') |
|
647 |
if cipher not in supported_ciphers: |
|
648 |
raise InternalError("Unsupported cipher in auth file: " |
|
649 |
"%s" % line) |
|
650 |
|
|
651 |
password = (cipher, m.group('pass')) |
|
652 |
|
|
653 |
if user in users: |
|
654 |
raise InternalError("Duplicate user entry in auth file") |
|
655 |
|
|
656 |
users[user] = password |
|
657 |
except IOError as err: |
|
658 |
logger.error("Error while reading the auth file:") |
|
629 |
lines = [l.strip().split(':', 1) for l in f.readlines()] |
|
630 |
for (user, passhash) in lines: |
|
631 |
users[user] = passhash.lstrip('$').split('$', 2) |
|
632 |
except ValueError as err: |
|
659 | 633 |
logger.exception(err) |
634 |
raise InternalError("Malformed auth file") |
|
660 | 635 |
|
661 | 636 |
if not users: |
662 | 637 |
logger.warning("No users defined") |
Also available in: Unified diff