blob: b4f6ea6991aa2f9f840a3851420d4a7492761719 [file] [log] [blame]
SF initial configuratora26c41e2022-10-06 13:33:13 +03001# Copyright 2018 Red Hat, Inc.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
15import argparse
16import os
17import socket
18import struct
19import sys
20import re
21
22from ansible.module_utils.basic import AnsibleModule
23
24
25SSH_AGENT_FAILURE = 5
26SSH_AGENT_SUCCESS = 6
27SSH_AGENT_IDENTITIES_ANSWER = 12
28
29SSH_AGENTC_REQUEST_IDENTITIES = 11
30SSH_AGENTC_REMOVE_IDENTITY = 18
31
32
33def unpack_string(data):
34 (l,) = struct.unpack('!i', data[:4])
35 d = data[4:4 + l]
36 return (d, data[4 + l:])
37
38
39def pack_string(data):
40 ret = struct.pack('!i', len(data))
41 return ret + data
42
43
44class Agent(object):
45 def __init__(self):
46 path = os.environ['SSH_AUTH_SOCK']
47 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
48 self.sock.connect(path)
49
50 def send(self, message_type, contents):
51 payload = struct.pack('!ib', len(contents) + 1, message_type)
52 payload += bytearray(contents)
53 self.sock.send(payload)
54
55 def recv(self):
56 buf = b''
57 while len(buf) < 5:
58 buf += self.sock.recv(1)
59 message_len, message_type = struct.unpack('!ib', buf[:5])
60 buf = buf[5:]
61 while len(buf) < message_len - 1:
62 buf += self.sock.recv(1)
63 return message_type, buf
64
65 def list(self):
66 self.send(SSH_AGENTC_REQUEST_IDENTITIES, b'')
67 mtype, data = self.recv()
68 if mtype != SSH_AGENT_IDENTITIES_ANSWER:
69 raise Exception("Invalid response to list")
70 (nkeys,) = struct.unpack('!i', data[:4])
71 data = data[4:]
72 keys = []
73 for i in range(nkeys):
74 blob, data = unpack_string(data)
75 comment, data = unpack_string(data)
76 keys.append((blob, comment))
77 return keys
78
79 def remove(self, blob):
80 self.send(SSH_AGENTC_REMOVE_IDENTITY, pack_string(blob))
81 mtype, data = self.recv()
82 if mtype != SSH_AGENT_SUCCESS:
83 raise Exception("Key was not removed")
84
85
86def run(remove):
87 a = Agent()
88 keys = a.list()
89 removed = []
90 to_remove = re.compile(remove)
91 for blob, comment in keys:
92 if not to_remove.match(comment.decode('utf8')):
93 continue
94 a.remove(blob)
95 removed.append(comment)
96 return removed
97
98
99def ansible_main():
100 module = AnsibleModule(
101 argument_spec=dict(
102 remove=dict(required=True, type='str')))
103
104 removed = run(module.params.get('remove'))
105
106 module.exit_json(changed=(removed != []),
107 removed=removed)
108
109
110def cli_main():
111 parser = argparse.ArgumentParser(
112 description="Remove ssh keys from agent"
113 )
114 parser.add_argument('remove', nargs='+',
115 help='regex matching comments of keys to remove')
116 args = parser.parse_args()
117
118 removed = run(args.remove)
119 print(removed)
120
121
122if __name__ == '__main__':
123 if sys.stdin.isatty():
124 cli_main()
125 else:
126 ansible_main()