|
1 | | -import binascii |
2 | 1 | import logging |
3 | | -import os |
4 | 2 | import sys |
5 | 3 | import threading |
6 | 4 | import warnings |
|
19 | 17 | except ImportError: # pragma: no cover |
20 | 18 | from ordereddict import OrderedDict |
21 | 19 |
|
22 | | -if sys.version[0] == '2': |
23 | | - from Queue import Queue |
24 | | -else: |
25 | | - from queue import Queue |
26 | | - |
27 | 20 | log = logging.getLogger(__name__) |
28 | 21 |
|
29 | 22 |
|
@@ -108,84 +101,66 @@ def __init__(self): |
108 | 101 | super(FSCTLPipeWait, self).__init__() |
109 | 102 |
|
110 | 103 |
|
111 | | -class _NamedPipe(threading.Thread): |
112 | | - |
113 | | - ACCESS_MASK = 0 |
| 104 | +class InputPipe(object): |
114 | 105 |
|
115 | 106 | def __init__(self, tree, name): |
116 | | - super(_NamedPipe, self).__init__() |
117 | | - log.info("Initialising Named Pipe with the name: %s" % name) |
| 107 | + """ |
| 108 | + Thin wrapper around an input Named Pipe. This isn't run in a thread |
| 109 | + and any data sent to write is written to the Named Pipe. |
| 110 | +
|
| 111 | + :param tree: The SMB tree connected to IPC$ |
| 112 | + :param name: The name of the input Named Pipe |
| 113 | + """ |
| 114 | + log.info("Initialising Input Named Pipe with the name: %s" % name) |
118 | 115 | self.name = name |
119 | 116 | self.connection = tree.session.connection |
120 | 117 | self.sid = tree.session.session_id |
121 | 118 | self.tid = tree.tree_connect_id |
122 | 119 | self.pipe = open_pipe(tree, name, |
123 | | - self.ACCESS_MASK, |
| 120 | + FilePipePrinterAccessMask.FILE_WRITE_DATA | |
| 121 | + FilePipePrinterAccessMask.FILE_APPEND_DATA | |
| 122 | + FilePipePrinterAccessMask.FILE_WRITE_EA | |
| 123 | + FilePipePrinterAccessMask.FILE_WRITE_ATTRIBUTES | |
| 124 | + FilePipePrinterAccessMask.FILE_READ_ATTRIBUTES | |
| 125 | + FilePipePrinterAccessMask.READ_CONTROL | |
| 126 | + FilePipePrinterAccessMask.SYNCHRONIZE, |
124 | 127 | fsctl_wait=True) |
125 | 128 |
|
126 | | - def _close_thread(self): |
127 | | - self.join(timeout=5) |
128 | | - if self.is_alive(): |
129 | | - warnings.warn("Timeout while waiting for pipe thread to close: %s" |
130 | | - % self.name, TheadCloseTimeoutWarning) |
131 | | - |
132 | | - |
133 | | -class InputPipe(_NamedPipe): |
134 | | - |
135 | | - ACCESS_MASK = FilePipePrinterAccessMask.FILE_WRITE_DATA | \ |
136 | | - FilePipePrinterAccessMask.FILE_APPEND_DATA | \ |
137 | | - FilePipePrinterAccessMask.FILE_WRITE_EA | \ |
138 | | - FilePipePrinterAccessMask.FILE_WRITE_ATTRIBUTES | \ |
139 | | - FilePipePrinterAccessMask.FILE_READ_ATTRIBUTES | \ |
140 | | - FilePipePrinterAccessMask.READ_CONTROL | \ |
141 | | - FilePipePrinterAccessMask.SYNCHRONIZE |
142 | | - |
143 | | - def __init__(self, tree, name): |
144 | | - super(InputPipe, self).__init__(tree, name) |
145 | | - self.pipe_buffer = Queue() |
146 | | - self.close_bytes = os.urandom(16) |
147 | | - log.debug("Shutdown bytes for input pipe: %s" |
148 | | - % binascii.hexlify(self.close_bytes)) |
149 | | - self.pipe_buffer = Queue() |
150 | | - |
151 | | - def run(self): |
152 | | - try: |
153 | | - log.debug("Starting thread of Input Named Pipe: %s" % self.name) |
154 | | - while True: |
155 | | - log.debug("Waiting for input for %s" % self.name) |
156 | | - input_data = self.pipe_buffer.get() |
157 | | - log.debug("Input for %s was found: %s" |
158 | | - % (self.name, binascii.hexlify(input_data))) |
159 | | - if input_data == self.close_bytes: |
160 | | - log.debug("Close bytes was received for input pipe: %s" |
161 | | - % self.name) |
162 | | - break |
163 | | - |
164 | | - log.debug("Writing bytes to Input Named Pipe: %s" % self.name) |
165 | | - self.pipe.write(input_data, 0) |
166 | | - finally: |
167 | | - log.debug("Closing SMB Open to Input Named Pipe: %s" % self.name) |
168 | | - self.pipe.close(get_attributes=False) |
169 | | - log.debug("Input Named Pipe %s thread finished" % self.name) |
| 129 | + def write(self, data): |
| 130 | + log.info("Sending bytes to Input Named Pipe: %s" % self.name) |
| 131 | + self.pipe.write(data, 0) |
170 | 132 |
|
171 | 133 | def close(self): |
172 | 134 | log.info("Closing Input Named Pipe: %s" % self.name) |
173 | | - log.debug("Send shutdown bytes to Input Named Pipe: %s" % self.name) |
174 | | - self.pipe_buffer.put(self.close_bytes) |
175 | | - self._close_thread() |
176 | | - |
| 135 | + self.pipe.close(get_attributes=False) |
177 | 136 |
|
178 | | -class OutputPipe(with_metaclass(ABCMeta, _NamedPipe)): |
179 | 137 |
|
180 | | - ACCESS_MASK = FilePipePrinterAccessMask.FILE_READ_DATA | \ |
181 | | - FilePipePrinterAccessMask.FILE_READ_ATTRIBUTES | \ |
182 | | - FilePipePrinterAccessMask.FILE_READ_EA | \ |
183 | | - FilePipePrinterAccessMask.READ_CONTROL | \ |
184 | | - FilePipePrinterAccessMask.SYNCHRONIZE |
| 138 | +class OutputPipe(with_metaclass(ABCMeta, threading.Thread)): |
185 | 139 |
|
186 | 140 | def __init__(self, tree, name): |
187 | | - """Generic Output/Read Pipe that stores the output read in a Queue""" |
188 | | - super(OutputPipe, self).__init__(tree, name) |
| 141 | + """ |
| 142 | + Base class for an Output/Read pipe that reads the output from a Named |
| 143 | + Pipe in a separate thread and sends that data to the handle_output |
| 144 | + method defined by the implementation class. This should not be used |
| 145 | + directly, i.e. use OutputPipeBytes instead which returns the Named |
| 146 | + Pipe output as a byte string. |
| 147 | +
|
| 148 | + :param tree: The SMB tree connected to IPC$ |
| 149 | + :param name: The name of the output Named Pipe |
| 150 | + """ |
| 151 | + super(OutputPipe, self).__init__() |
| 152 | + log.info("Initialising Output Named Pipe with the name: %s" % name) |
| 153 | + self.name = name |
| 154 | + self.connection = tree.session.connection |
| 155 | + self.sid = tree.session.session_id |
| 156 | + self.tid = tree.tree_connect_id |
| 157 | + self.pipe = open_pipe(tree, name, |
| 158 | + FilePipePrinterAccessMask.FILE_READ_DATA | |
| 159 | + FilePipePrinterAccessMask.FILE_READ_ATTRIBUTES | |
| 160 | + FilePipePrinterAccessMask.FILE_READ_EA | |
| 161 | + FilePipePrinterAccessMask.READ_CONTROL | |
| 162 | + FilePipePrinterAccessMask.SYNCHRONIZE, |
| 163 | + fsctl_wait=True) |
189 | 164 | self.sent_first = False |
190 | 165 |
|
191 | 166 | def run(self): |
@@ -253,12 +228,16 @@ def get_output(self): |
253 | 228 |
|
254 | 229 | def close(self): |
255 | 230 | log.info("Closing Output Named Pipe: %s" % self.name) |
256 | | - self._close_thread() |
| 231 | + self.join(timeout=5) |
| 232 | + if self.is_alive(): |
| 233 | + warnings.warn("Timeout while waiting for pipe thread to close: %s" |
| 234 | + % self.name, TheadCloseTimeoutWarning) |
257 | 235 |
|
258 | 236 |
|
259 | 237 | class OutputPipeBytes(OutputPipe): |
260 | 238 |
|
261 | 239 | def __init__(self, tree, name): |
| 240 | + """ An impl of OuputPipe that stores the output buffer as bytes""" |
262 | 241 | self.pipe_buffer = b"" |
263 | 242 | super(OutputPipeBytes, self).__init__(tree, name) |
264 | 243 |
|
|
0 commit comments