/
usr
/
lib
/
python2.6
/
site-packages
/
cloudinit
/
/usr/lib/python2.6/site-packages/cloudinit
mkdir
upload
Name
Size
Mode
Actions
config/
-
0755
rm
distros/
-
0755
rm
filters/
-
0755
rm
handlers/
-
0755
rm
mergers/
-
0755
rm
sources/
-
0755
rm
cloud.py
3497
0644
edit
dl
rm
cloud.pyc
3723
0644
edit
dl
rm
cloud.pyo
3723
0644
edit
dl
rm
cs_utils.py
3321
0644
edit
dl
rm
cs_utils.pyc
4266
0644
edit
dl
rm
cs_utils.pyo
4266
0644
edit
dl
rm
ec2_utils.py
6577
0644
edit
dl
rm
ec2_utils.pyc
5755
0644
edit
dl
rm
ec2_utils.pyo
5755
0644
edit
dl
rm
helpers.py
15045
0644
edit
dl
rm
helpers.pyc
16600
0644
edit
dl
rm
helpers.pyo
16600
0644
edit
dl
rm
importer.py
2317
0644
edit
dl
rm
importer.pyc
1502
0644
edit
dl
rm
importer.pyo
1502
0644
edit
dl
rm
log.py
4620
0644
edit
dl
rm
log.pyc
3700
0644
edit
dl
rm
log.pyo
3700
0644
edit
dl
rm
netinfo.py
6854
0644
edit
dl
rm
netinfo.pyc
5347
0644
edit
dl
rm
netinfo.pyo
5347
0644
edit
dl
rm
patcher.py
1820
0644
edit
dl
rm
patcher.pyc
1531
0644
edit
dl
rm
patcher.pyo
1531
0644
edit
dl
rm
safeyaml.py
1060
0644
edit
dl
rm
safeyaml.pyc
891
0644
edit
dl
rm
safeyaml.pyo
891
0644
edit
dl
rm
settings.py
2111
0644
edit
dl
rm
settings.pyc
1035
0644
edit
dl
rm
settings.pyo
1035
0644
edit
dl
rm
signal_handler.py
2378
0644
edit
dl
rm
signal_handler.pyc
2326
0644
edit
dl
rm
signal_handler.pyo
2326
0644
edit
dl
rm
ssh_util.py
10636
0644
edit
dl
rm
ssh_util.pyc
10072
0644
edit
dl
rm
ssh_util.pyo
10072
0644
edit
dl
rm
stages.py
27944
0644
edit
dl
rm
stages.pyc
21399
0644
edit
dl
rm
stages.pyo
21399
0644
edit
dl
rm
templater.py
1362
0644
edit
dl
rm
templater.pyc
1003
0644
edit
dl
rm
templater.pyo
1003
0644
edit
dl
rm
type_utils.py
1224
0644
edit
dl
rm
type_utils.pyc
524
0644
edit
dl
rm
type_utils.pyo
524
0644
edit
dl
rm
url_helper.py
12852
0644
edit
dl
rm
url_helper.pyc
11295
0644
edit
dl
rm
url_helper.pyo
11295
0644
edit
dl
rm
user_data.py
13143
0644
edit
dl
rm
user_data.pyc
9569
0644
edit
dl
rm
user_data.pyo
9569
0644
edit
dl
rm
util.py
62259
0644
edit
dl
rm
util.pyc
57445
0644
edit
dl
rm
util.pyo
57445
0644
edit
dl
rm
version.py
854
0644
edit
dl
rm
version.pyc
561
0644
edit
dl
rm
version.pyo
561
0644
edit
dl
rm
__init__.py
925
0644
edit
dl
rm
__init__.pyc
141
0644
edit
dl
rm
__init__.pyo
141
0644
edit
dl
rm
Edit:
/usr/lib/python2.6/site-packages/cloudinit/ssh_util.py
(10636B)
#!/usr/bin/python # vi: ts=4 expandtab # # Copyright (C) 2012 Canonical Ltd. # Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # # Author: Scott Moser <scott.moser@canonical.com> # Author: Juerg Hafliger <juerg.haefliger@hp.com> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. import os import pwd from cloudinit import log as logging from cloudinit import util LOG = logging.getLogger(__name__) # See: man sshd_config DEF_SSHD_CFG = "/etc/ssh/sshd_config" # taken from openssh source key.c/key_type_from_name VALID_KEY_TYPES = ("rsa", "dsa", "ssh-rsa", "ssh-dss", "ecdsa", "ssh-rsa-cert-v00@openssh.com", "ssh-dss-cert-v00@openssh.com", "ssh-rsa-cert-v00@openssh.com", "ssh-dss-cert-v00@openssh.com", "ssh-rsa-cert-v01@openssh.com", "ssh-dss-cert-v01@openssh.com", "ecdsa-sha2-nistp256-cert-v01@openssh.com", "ecdsa-sha2-nistp384-cert-v01@openssh.com", "ecdsa-sha2-nistp521-cert-v01@openssh.com") class AuthKeyLine(object): def __init__(self, source, keytype=None, base64=None, comment=None, options=None): self.base64 = base64 self.comment = comment self.options = options self.keytype = keytype self.source = source def valid(self): return (self.base64 and self.keytype) def __str__(self): toks = [] if self.options: toks.append(self.options) if self.keytype: toks.append(self.keytype) if self.base64: toks.append(self.base64) if self.comment: toks.append(self.comment) if not toks: return self.source else: return ' '.join(toks) class AuthKeyLineParser(object): """ AUTHORIZED_KEYS FILE FORMAT AuthorizedKeysFile specifies the file containing public keys for public key authentication; if none is specified, the default is ~/.ssh/authorized_keys. Each line of the file contains one key (empty (because of the size of the public key encoding) up to a limit of 8 kilo- bytes, which permits DSA keys up to 8 kilobits and RSA keys up to 16 kilobits. You don't want to type them in; instead, copy the identity.pub, id_dsa.pub, or the id_rsa.pub file and edit it. sshd enforces a minimum RSA key modulus size for protocol 1 and protocol 2 keys of 768 bits. The options (if present) consist of comma-separated option specifica- tions. No spaces are permitted, except within double quotes. The fol- lowing option specifications are supported (note that option keywords are case-insensitive): """ def _extract_options(self, ent): """ The options (if present) consist of comma-separated option specifica- tions. No spaces are permitted, except within double quotes. Note that option keywords are case-insensitive. """ quoted = False i = 0 while (i < len(ent) and ((quoted) or (ent[i] not in (" ", "\t")))): curc = ent[i] if i + 1 >= len(ent): i = i + 1 break nextc = ent[i + 1] if curc == "\\" and nextc == '"': i = i + 1 elif curc == '"': quoted = not quoted i = i + 1 options = ent[0:i] # Return the rest of the string in 'remain' remain = ent[i:].lstrip() return (options, remain) def parse(self, src_line, options=None): # modeled after opensshes auth2-pubkey.c:user_key_allowed2 line = src_line.rstrip("\r\n") if line.startswith("#") or line.strip() == '': return AuthKeyLine(src_line) def parse_ssh_key(ent): # return ketype, key, [comment] toks = ent.split(None, 2) if len(toks) < 2: raise TypeError("To few fields: %s" % len(toks)) if toks[0] not in VALID_KEY_TYPES: raise TypeError("Invalid keytype %s" % toks[0]) # valid key type and 2 or 3 fields: if len(toks) == 2: # no comment in line toks.append("") return toks ent = line.strip() try: (keytype, base64, comment) = parse_ssh_key(ent) except TypeError: (keyopts, remain) = self._extract_options(ent) if options is None: options = keyopts try: (keytype, base64, comment) = parse_ssh_key(remain) except TypeError: return AuthKeyLine(src_line) return AuthKeyLine(src_line, keytype=keytype, base64=base64, comment=comment, options=options) def parse_authorized_keys(fname): lines = [] try: if os.path.isfile(fname): lines = util.load_file(fname).splitlines() except (IOError, OSError): util.logexc(LOG, "Error reading lines from %s", fname) lines = [] parser = AuthKeyLineParser() contents = [] for line in lines: contents.append(parser.parse(line)) return contents def update_authorized_keys(old_entries, keys): to_add = list(keys) for i in range(0, len(old_entries)): ent = old_entries[i] if not ent.valid(): continue # Replace those with the same base64 for k in keys: if not ent.valid(): continue if k.base64 == ent.base64: # Replace it with our better one ent = k # Don't add it later if k in to_add: to_add.remove(k) old_entries[i] = ent # Now append any entries we did not match above for key in to_add: old_entries.append(key) # Now format them back to strings... lines = [str(b) for b in old_entries] # Ensure it ends with a newline lines.append('') return '\n'.join(lines) def users_ssh_info(username): pw_ent = pwd.getpwnam(username) if not pw_ent or not pw_ent.pw_dir: raise RuntimeError("Unable to get ssh info for user %r" % (username)) return (os.path.join(pw_ent.pw_dir, '.ssh'), pw_ent) def extract_authorized_keys(username): (ssh_dir, pw_ent) = users_ssh_info(username) auth_key_fn = None with util.SeLinuxGuard(ssh_dir, recursive=True): try: # The 'AuthorizedKeysFile' may contain tokens # of the form %T which are substituted during connection set-up. # The following tokens are defined: %% is replaced by a literal # '%', %h is replaced by the home directory of the user being # authenticated and %u is replaced by the username of that user. ssh_cfg = parse_ssh_config_map(DEF_SSHD_CFG) auth_key_fn = ssh_cfg.get("authorizedkeysfile", '').strip() if not auth_key_fn: auth_key_fn = "%h/.ssh/authorized_keys" auth_key_fn = auth_key_fn.replace("%h", pw_ent.pw_dir) auth_key_fn = auth_key_fn.replace("%u", username) auth_key_fn = auth_key_fn.replace("%%", '%') if not auth_key_fn.startswith('/'): auth_key_fn = os.path.join(pw_ent.pw_dir, auth_key_fn) except (IOError, OSError): # Give up and use a default key filename auth_key_fn = os.path.join(ssh_dir, 'authorized_keys') util.logexc(LOG, "Failed extracting 'AuthorizedKeysFile' in ssh " "config from %r, using 'AuthorizedKeysFile' file " "%r instead", DEF_SSHD_CFG, auth_key_fn) return (auth_key_fn, parse_authorized_keys(auth_key_fn)) def setup_user_keys(keys, username, options=None): # Make sure the users .ssh dir is setup accordingly (ssh_dir, pwent) = users_ssh_info(username) if not os.path.isdir(ssh_dir): util.ensure_dir(ssh_dir, mode=0700) util.chownbyid(ssh_dir, pwent.pw_uid, pwent.pw_gid) # Turn the 'update' keys given into actual entries parser = AuthKeyLineParser() key_entries = [] for k in keys: key_entries.append(parser.parse(str(k), options=options)) # Extract the old and make the new (auth_key_fn, auth_key_entries) = extract_authorized_keys(username) with util.SeLinuxGuard(ssh_dir, recursive=True): content = update_authorized_keys(auth_key_entries, key_entries) util.ensure_dir(os.path.dirname(auth_key_fn), mode=0700) util.write_file(auth_key_fn, content, mode=0600) util.chownbyid(auth_key_fn, pwent.pw_uid, pwent.pw_gid) class SshdConfigLine(object): def __init__(self, line, k=None, v=None): self.line = line self._key = k self.value = v @property def key(self): if self._key is None: return None # Keywords are case-insensitive return self._key.lower() def __str__(self): if self._key is None: return str(self.line) else: v = str(self._key) if self.value: v += " " + str(self.value) return v def parse_ssh_config(fname): # See: man sshd_config # The file contains keyword-argument pairs, one per line. # Lines starting with '#' and empty lines are interpreted as comments. # Note: key-words are case-insensitive and arguments are case-sensitive lines = [] if not os.path.isfile(fname): return lines for line in util.load_file(fname).splitlines(): line = line.strip() if not line or line.startswith("#"): lines.append(SshdConfigLine(line)) continue (key, val) = line.split(None, 1) lines.append(SshdConfigLine(line, key, val)) return lines def parse_ssh_config_map(fname): lines = parse_ssh_config(fname) if not lines: return {} ret = {} for line in lines: if not line.key: continue ret[line.key] = line.value return ret
Save
cmd:
run