| 1 | # Copyright (c) Twisted Matrix Laboratories. |
|---|
| 2 | # See LICENSE for details. |
|---|
| 3 | |
|---|
| 4 | """ |
|---|
| 5 | This module contains interfaces defined for the L{twisted.conch} package. |
|---|
| 6 | """ |
|---|
| 7 | |
|---|
| 8 | from zope.interface import Interface, Attribute |
|---|
| 9 | |
|---|
| 10 | class IConchUser(Interface): |
|---|
| 11 | """ |
|---|
| 12 | A user who has been authenticated to Cred through Conch. This is |
|---|
| 13 | the interface between the SSH connection and the user. |
|---|
| 14 | """ |
|---|
| 15 | |
|---|
| 16 | conn = Attribute('The SSHConnection object for this user.') |
|---|
| 17 | |
|---|
| 18 | def lookupChannel(channelType, windowSize, maxPacket, data): |
|---|
| 19 | """ |
|---|
| 20 | The other side requested a channel of some sort. |
|---|
| 21 | channelType is the type of channel being requested, |
|---|
| 22 | windowSize is the initial size of the remote window, |
|---|
| 23 | maxPacket is the largest packet we should send, |
|---|
| 24 | data is any other packet data (often nothing). |
|---|
| 25 | |
|---|
| 26 | We return a subclass of L{SSHChannel<ssh.channel.SSHChannel>}. If |
|---|
| 27 | an appropriate channel can not be found, an exception will be |
|---|
| 28 | raised. If a L{ConchError<error.ConchError>} is raised, the .value |
|---|
| 29 | will be the message, and the .data will be the error code. |
|---|
| 30 | |
|---|
| 31 | @type channelType: C{str} |
|---|
| 32 | @type windowSize: C{int} |
|---|
| 33 | @type maxPacket: C{int} |
|---|
| 34 | @type data: C{str} |
|---|
| 35 | @rtype: subclass of L{SSHChannel}/C{tuple} |
|---|
| 36 | """ |
|---|
| 37 | |
|---|
| 38 | def lookupSubsystem(subsystem, data): |
|---|
| 39 | """ |
|---|
| 40 | The other side requested a subsystem. |
|---|
| 41 | subsystem is the name of the subsystem being requested. |
|---|
| 42 | data is any other packet data (often nothing). |
|---|
| 43 | |
|---|
| 44 | We return a L{Protocol}. |
|---|
| 45 | """ |
|---|
| 46 | |
|---|
| 47 | def gotGlobalRequest(requestType, data): |
|---|
| 48 | """ |
|---|
| 49 | A global request was sent from the other side. |
|---|
| 50 | |
|---|
| 51 | By default, this dispatches to a method 'channel_channelType' with any |
|---|
| 52 | non-alphanumerics in the channelType replace with _'s. If it cannot |
|---|
| 53 | find a suitable method, it returns an OPEN_UNKNOWN_CHANNEL_TYPE error. |
|---|
| 54 | The method is called with arguments of windowSize, maxPacket, data. |
|---|
| 55 | """ |
|---|
| 56 | |
|---|
| 57 | class ISession(Interface): |
|---|
| 58 | |
|---|
| 59 | def getPty(term, windowSize, modes): |
|---|
| 60 | """ |
|---|
| 61 | Get a psuedo-terminal for use by a shell or command. |
|---|
| 62 | |
|---|
| 63 | If a psuedo-terminal is not available, or the request otherwise |
|---|
| 64 | fails, raise an exception. |
|---|
| 65 | """ |
|---|
| 66 | |
|---|
| 67 | def openShell(proto): |
|---|
| 68 | """ |
|---|
| 69 | Open a shell and connect it to proto. |
|---|
| 70 | |
|---|
| 71 | @param proto: a L{ProcessProtocol} instance. |
|---|
| 72 | """ |
|---|
| 73 | |
|---|
| 74 | def execCommand(proto, command): |
|---|
| 75 | """ |
|---|
| 76 | Execute a command. |
|---|
| 77 | |
|---|
| 78 | @param proto: a L{ProcessProtocol} instance. |
|---|
| 79 | """ |
|---|
| 80 | |
|---|
| 81 | def windowChanged(newWindowSize): |
|---|
| 82 | """ |
|---|
| 83 | Called when the size of the remote screen has changed. |
|---|
| 84 | """ |
|---|
| 85 | |
|---|
| 86 | def eofReceived(): |
|---|
| 87 | """ |
|---|
| 88 | Called when the other side has indicated no more data will be sent. |
|---|
| 89 | """ |
|---|
| 90 | |
|---|
| 91 | def closed(): |
|---|
| 92 | """ |
|---|
| 93 | Called when the session is closed. |
|---|
| 94 | """ |
|---|
| 95 | |
|---|
| 96 | |
|---|
| 97 | class ISFTPServer(Interface): |
|---|
| 98 | """ |
|---|
| 99 | The only attribute of this class is "avatar". It is the avatar |
|---|
| 100 | returned by the Realm that we are authenticated with, and |
|---|
| 101 | represents the logged-in user. Each method should check to verify |
|---|
| 102 | that the user has permission for their actions. |
|---|
| 103 | """ |
|---|
| 104 | |
|---|
| 105 | def gotVersion(otherVersion, extData): |
|---|
| 106 | """ |
|---|
| 107 | Called when the client sends their version info. |
|---|
| 108 | |
|---|
| 109 | otherVersion is an integer representing the version of the SFTP |
|---|
| 110 | protocol they are claiming. |
|---|
| 111 | extData is a dictionary of extended_name : extended_data items. |
|---|
| 112 | These items are sent by the client to indicate additional features. |
|---|
| 113 | |
|---|
| 114 | This method should return a dictionary of extended_name : extended_data |
|---|
| 115 | items. These items are the additional features (if any) supported |
|---|
| 116 | by the server. |
|---|
| 117 | """ |
|---|
| 118 | return {} |
|---|
| 119 | |
|---|
| 120 | def openFile(filename, flags, attrs): |
|---|
| 121 | """ |
|---|
| 122 | Called when the clients asks to open a file. |
|---|
| 123 | |
|---|
| 124 | @param filename: a string representing the file to open. |
|---|
| 125 | |
|---|
| 126 | @param flags: an integer of the flags to open the file with, ORed together. |
|---|
| 127 | The flags and their values are listed at the bottom of this file. |
|---|
| 128 | |
|---|
| 129 | @param attrs: a list of attributes to open the file with. It is a |
|---|
| 130 | dictionary, consisting of 0 or more keys. The possible keys are:: |
|---|
| 131 | |
|---|
| 132 | size: the size of the file in bytes |
|---|
| 133 | uid: the user ID of the file as an integer |
|---|
| 134 | gid: the group ID of the file as an integer |
|---|
| 135 | permissions: the permissions of the file with as an integer. |
|---|
| 136 | the bit representation of this field is defined by POSIX. |
|---|
| 137 | atime: the access time of the file as seconds since the epoch. |
|---|
| 138 | mtime: the modification time of the file as seconds since the epoch. |
|---|
| 139 | ext_*: extended attributes. The server is not required to |
|---|
| 140 | understand this, but it may. |
|---|
| 141 | |
|---|
| 142 | NOTE: there is no way to indicate text or binary files. it is up |
|---|
| 143 | to the SFTP client to deal with this. |
|---|
| 144 | |
|---|
| 145 | This method returns an object that meets the ISFTPFile interface. |
|---|
| 146 | Alternatively, it can return a L{Deferred} that will be called back |
|---|
| 147 | with the object. |
|---|
| 148 | """ |
|---|
| 149 | |
|---|
| 150 | def removeFile(filename): |
|---|
| 151 | """ |
|---|
| 152 | Remove the given file. |
|---|
| 153 | |
|---|
| 154 | This method returns when the remove succeeds, or a Deferred that is |
|---|
| 155 | called back when it succeeds. |
|---|
| 156 | |
|---|
| 157 | @param filename: the name of the file as a string. |
|---|
| 158 | """ |
|---|
| 159 | |
|---|
| 160 | def renameFile(oldpath, newpath): |
|---|
| 161 | """ |
|---|
| 162 | Rename the given file. |
|---|
| 163 | |
|---|
| 164 | This method returns when the rename succeeds, or a L{Deferred} that is |
|---|
| 165 | called back when it succeeds. If the rename fails, C{renameFile} will |
|---|
| 166 | raise an implementation-dependent exception. |
|---|
| 167 | |
|---|
| 168 | @param oldpath: the current location of the file. |
|---|
| 169 | @param newpath: the new file name. |
|---|
| 170 | """ |
|---|
| 171 | |
|---|
| 172 | def makeDirectory(path, attrs): |
|---|
| 173 | """ |
|---|
| 174 | Make a directory. |
|---|
| 175 | |
|---|
| 176 | This method returns when the directory is created, or a Deferred that |
|---|
| 177 | is called back when it is created. |
|---|
| 178 | |
|---|
| 179 | @param path: the name of the directory to create as a string. |
|---|
| 180 | @param attrs: a dictionary of attributes to create the directory with. |
|---|
| 181 | Its meaning is the same as the attrs in the L{openFile} method. |
|---|
| 182 | """ |
|---|
| 183 | |
|---|
| 184 | def removeDirectory(path): |
|---|
| 185 | """ |
|---|
| 186 | Remove a directory (non-recursively) |
|---|
| 187 | |
|---|
| 188 | It is an error to remove a directory that has files or directories in |
|---|
| 189 | it. |
|---|
| 190 | |
|---|
| 191 | This method returns when the directory is removed, or a Deferred that |
|---|
| 192 | is called back when it is removed. |
|---|
| 193 | |
|---|
| 194 | @param path: the directory to remove. |
|---|
| 195 | """ |
|---|
| 196 | |
|---|
| 197 | def openDirectory(path): |
|---|
| 198 | """ |
|---|
| 199 | Open a directory for scanning. |
|---|
| 200 | |
|---|
| 201 | This method returns an iterable object that has a close() method, |
|---|
| 202 | or a Deferred that is called back with same. |
|---|
| 203 | |
|---|
| 204 | The close() method is called when the client is finished reading |
|---|
| 205 | from the directory. At this point, the iterable will no longer |
|---|
| 206 | be used. |
|---|
| 207 | |
|---|
| 208 | The iterable should return triples of the form (filename, |
|---|
| 209 | longname, attrs) or Deferreds that return the same. The |
|---|
| 210 | sequence must support __getitem__, but otherwise may be any |
|---|
| 211 | 'sequence-like' object. |
|---|
| 212 | |
|---|
| 213 | filename is the name of the file relative to the directory. |
|---|
| 214 | logname is an expanded format of the filename. The recommended format |
|---|
| 215 | is: |
|---|
| 216 | -rwxr-xr-x 1 mjos staff 348911 Mar 25 14:29 t-filexfer |
|---|
| 217 | 1234567890 123 12345678 12345678 12345678 123456789012 |
|---|
| 218 | |
|---|
| 219 | The first line is sample output, the second is the length of the field. |
|---|
| 220 | The fields are: permissions, link count, user owner, group owner, |
|---|
| 221 | size in bytes, modification time. |
|---|
| 222 | |
|---|
| 223 | attrs is a dictionary in the format of the attrs argument to openFile. |
|---|
| 224 | |
|---|
| 225 | @param path: the directory to open. |
|---|
| 226 | """ |
|---|
| 227 | |
|---|
| 228 | def getAttrs(path, followLinks): |
|---|
| 229 | """ |
|---|
| 230 | Return the attributes for the given path. |
|---|
| 231 | |
|---|
| 232 | This method returns a dictionary in the same format as the attrs |
|---|
| 233 | argument to openFile or a Deferred that is called back with same. |
|---|
| 234 | |
|---|
| 235 | @param path: the path to return attributes for as a string. |
|---|
| 236 | @param followLinks: a boolean. If it is True, follow symbolic links |
|---|
| 237 | and return attributes for the real path at the base. If it is False, |
|---|
| 238 | return attributes for the specified path. |
|---|
| 239 | """ |
|---|
| 240 | |
|---|
| 241 | def setAttrs(path, attrs): |
|---|
| 242 | """ |
|---|
| 243 | Set the attributes for the path. |
|---|
| 244 | |
|---|
| 245 | This method returns when the attributes are set or a Deferred that is |
|---|
| 246 | called back when they are. |
|---|
| 247 | |
|---|
| 248 | @param path: the path to set attributes for as a string. |
|---|
| 249 | @param attrs: a dictionary in the same format as the attrs argument to |
|---|
| 250 | L{openFile}. |
|---|
| 251 | """ |
|---|
| 252 | |
|---|
| 253 | def readLink(path): |
|---|
| 254 | """ |
|---|
| 255 | Find the root of a set of symbolic links. |
|---|
| 256 | |
|---|
| 257 | This method returns the target of the link, or a Deferred that |
|---|
| 258 | returns the same. |
|---|
| 259 | |
|---|
| 260 | @param path: the path of the symlink to read. |
|---|
| 261 | """ |
|---|
| 262 | |
|---|
| 263 | def makeLink(linkPath, targetPath): |
|---|
| 264 | """ |
|---|
| 265 | Create a symbolic link. |
|---|
| 266 | |
|---|
| 267 | This method returns when the link is made, or a Deferred that |
|---|
| 268 | returns the same. |
|---|
| 269 | |
|---|
| 270 | @param linkPath: the pathname of the symlink as a string. |
|---|
| 271 | @param targetPath: the path of the target of the link as a string. |
|---|
| 272 | """ |
|---|
| 273 | |
|---|
| 274 | def realPath(path): |
|---|
| 275 | """ |
|---|
| 276 | Convert any path to an absolute path. |
|---|
| 277 | |
|---|
| 278 | This method returns the absolute path as a string, or a Deferred |
|---|
| 279 | that returns the same. |
|---|
| 280 | |
|---|
| 281 | @param path: the path to convert as a string. |
|---|
| 282 | """ |
|---|
| 283 | |
|---|
| 284 | def extendedRequest(extendedName, extendedData): |
|---|
| 285 | """ |
|---|
| 286 | This is the extension mechanism for SFTP. The other side can send us |
|---|
| 287 | arbitrary requests. |
|---|
| 288 | |
|---|
| 289 | If we don't implement the request given by extendedName, raise |
|---|
| 290 | NotImplementedError. |
|---|
| 291 | |
|---|
| 292 | The return value is a string, or a Deferred that will be called |
|---|
| 293 | back with a string. |
|---|
| 294 | |
|---|
| 295 | @param extendedName: the name of the request as a string. |
|---|
| 296 | @param extendedData: the data the other side sent with the request, |
|---|
| 297 | as a string. |
|---|
| 298 | """ |
|---|
| 299 | |
|---|
| 300 | |
|---|
| 301 | |
|---|
| 302 | class IKnownHostEntry(Interface): |
|---|
| 303 | """ |
|---|
| 304 | A L{IKnownHostEntry} is an entry in an OpenSSH-formatted C{known_hosts} |
|---|
| 305 | file. |
|---|
| 306 | |
|---|
| 307 | @since: 8.2 |
|---|
| 308 | """ |
|---|
| 309 | |
|---|
| 310 | def matchesKey(key): |
|---|
| 311 | """ |
|---|
| 312 | Return True if this entry matches the given Key object, False |
|---|
| 313 | otherwise. |
|---|
| 314 | |
|---|
| 315 | @param key: The key object to match against. |
|---|
| 316 | @type key: L{twisted.conch.ssh.Key} |
|---|
| 317 | """ |
|---|
| 318 | |
|---|
| 319 | |
|---|
| 320 | def matchesHost(hostname): |
|---|
| 321 | """ |
|---|
| 322 | Return True if this entry matches the given hostname, False otherwise. |
|---|
| 323 | |
|---|
| 324 | Note that this does no name resolution; if you want to match an IP |
|---|
| 325 | address, you have to resolve it yourself, and pass it in as a dotted |
|---|
| 326 | quad string. |
|---|
| 327 | |
|---|
| 328 | @param key: The hostname to match against. |
|---|
| 329 | @type key: L{str} |
|---|
| 330 | """ |
|---|
| 331 | |
|---|
| 332 | |
|---|
| 333 | def toString(): |
|---|
| 334 | """ |
|---|
| 335 | @return: a serialized string representation of this entry, suitable for |
|---|
| 336 | inclusion in a known_hosts file. (Newline not included.) |
|---|
| 337 | |
|---|
| 338 | @rtype: L{str} |
|---|
| 339 | """ |
|---|
| 340 | |
|---|
| 341 | |
|---|
| 342 | |
|---|
| 343 | class ISFTPFile(Interface): |
|---|
| 344 | """ |
|---|
| 345 | This represents an open file on the server. An object adhering to this |
|---|
| 346 | interface should be returned from L{openFile}(). |
|---|
| 347 | """ |
|---|
| 348 | |
|---|
| 349 | def close(): |
|---|
| 350 | """ |
|---|
| 351 | Close the file. |
|---|
| 352 | |
|---|
| 353 | This method returns nothing if the close succeeds immediately, or a |
|---|
| 354 | Deferred that is called back when the close succeeds. |
|---|
| 355 | """ |
|---|
| 356 | |
|---|
| 357 | def readChunk(offset, length): |
|---|
| 358 | """ |
|---|
| 359 | Read from the file. |
|---|
| 360 | |
|---|
| 361 | If EOF is reached before any data is read, raise EOFError. |
|---|
| 362 | |
|---|
| 363 | This method returns the data as a string, or a Deferred that is |
|---|
| 364 | called back with same. |
|---|
| 365 | |
|---|
| 366 | @param offset: an integer that is the index to start from in the file. |
|---|
| 367 | @param length: the maximum length of data to return. The actual amount |
|---|
| 368 | returned may less than this. For normal disk files, however, |
|---|
| 369 | this should read the requested number (up to the end of the file). |
|---|
| 370 | """ |
|---|
| 371 | |
|---|
| 372 | def writeChunk(offset, data): |
|---|
| 373 | """ |
|---|
| 374 | Write to the file. |
|---|
| 375 | |
|---|
| 376 | This method returns when the write completes, or a Deferred that is |
|---|
| 377 | called when it completes. |
|---|
| 378 | |
|---|
| 379 | @param offset: an integer that is the index to start from in the file. |
|---|
| 380 | @param data: a string that is the data to write. |
|---|
| 381 | """ |
|---|
| 382 | |
|---|
| 383 | def getAttrs(): |
|---|
| 384 | """ |
|---|
| 385 | Return the attributes for the file. |
|---|
| 386 | |
|---|
| 387 | This method returns a dictionary in the same format as the attrs |
|---|
| 388 | argument to L{openFile} or a L{Deferred} that is called back with same. |
|---|
| 389 | """ |
|---|
| 390 | |
|---|
| 391 | def setAttrs(attrs): |
|---|
| 392 | """ |
|---|
| 393 | Set the attributes for the file. |
|---|
| 394 | |
|---|
| 395 | This method returns when the attributes are set or a Deferred that is |
|---|
| 396 | called back when they are. |
|---|
| 397 | |
|---|
| 398 | @param attrs: a dictionary in the same format as the attrs argument to |
|---|
| 399 | L{openFile}. |
|---|
| 400 | """ |
|---|
| 401 | |
|---|