1# 2# Copyright (C) 2010-2017 Samuel Abels 3# The MIT License (MIT) 4# 5# Permission is hereby granted, free of charge, to any person obtaining 6# a copy of this software and associated documentation files 7# (the "Software"), to deal in the Software without restriction, 8# including without limitation the rights to use, copy, modify, merge, 9# publish, distribute, sublicense, and/or sell copies of the Software, 10# and to permit persons to whom the Software is furnished to do so, 11# subject to the following conditions: 12# 13# The above copyright notice and this permission notice shall be 14# included in all copies or substantial portions of the Software. 15# 16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23from Exscript import Account 24from Exscript.stdlib.util import secure_function 25 26 27@secure_function 28def authenticate(scope): 29 """ 30 Looks for any username/password prompts on the current connection 31 and logs in using the login information that was passed to Exscript. 32 """ 33 scope.get('__connection__').app_authenticate() 34 return True 35 36 37@secure_function 38def authenticate_user(scope, user=[None], password=[None]): 39 """ 40 Like authenticate(), but logs in using the given user and password. 41 If a user and password are not given, the function uses the same 42 user and password that were used at the last login attempt; it is 43 an error if no such attempt was made before. 44 45 :type user: string 46 :param user: A username. 47 :type password: string 48 :param password: A password. 49 """ 50 conn = scope.get('__connection__') 51 user = user[0] 52 if user is None: 53 conn.app_authenticate() 54 else: 55 account = Account(user, password[0]) 56 conn.app_authenticate(account) 57 return True 58 59 60@secure_function 61def authorize(scope, password=[None]): 62 """ 63 Looks for a password prompt on the current connection 64 and enters the given password. 65 If a password is not given, the function uses the same 66 password that was used at the last login attempt; it is 67 an error if no such attempt was made before. 68 69 :type password: string 70 :param password: A password. 71 """ 72 conn = scope.get('__connection__') 73 password = password[0] 74 if password is None: 75 conn.app_authorize() 76 else: 77 account = Account('', password) 78 conn.app_authorize(account) 79 return True 80 81 82@secure_function 83def auto_authorize(scope, password=[None]): 84 """ 85 Executes a command on the remote host that causes an authorization 86 procedure to be started, then authorizes using the given password 87 in the same way in which authorize() works. 88 Depending on the detected operating system of the remote host the 89 following commands are started: 90 91 - on IOS, the "enable" command is executed. 92 - nothing on other operating systems yet. 93 94 :type password: string 95 :param password: A password. 96 """ 97 conn = scope.get('__connection__') 98 password = password[0] 99 if password is None: 100 conn.auto_app_authorize() 101 else: 102 account = Account('', password) 103 conn.auto_app_authorize(account) 104 return True 105 106 107@secure_function 108def autoinit(scope): 109 """ 110 Make the remote host more script-friendly by automatically executing 111 one or more commands on it. 112 The commands executed depend on the currently used driver. 113 For example, the driver for Cisco IOS would execute the 114 following commands:: 115 116 term len 0 117 term width 0 118 """ 119 scope.get('__connection__').autoinit() 120 return True 121 122 123@secure_function 124def close(scope): 125 """ 126 Closes the existing connection with the remote host. This function is 127 rarely used, as normally Exscript closes the connection automatically 128 when the script has completed. 129 """ 130 conn = scope.get('__connection__') 131 conn.close(1) 132 scope.define(__response__=conn.response) 133 return True 134 135 136@secure_function 137def exec_(scope, data): 138 """ 139 Sends the given data to the remote host and waits until the host 140 has responded with a prompt. 141 If the given data is a list of strings, each item is sent, and 142 after each item a prompt is expected. 143 144 This function also causes the response of the command to be stored 145 in the built-in __response__ variable. 146 147 :type data: string 148 :param data: The data that is sent. 149 """ 150 conn = scope.get('__connection__') 151 response = [] 152 for line in data: 153 conn.send(line) 154 conn.expect_prompt() 155 response += conn.response.split('\n')[1:] 156 scope.define(__response__=response) 157 return True 158 159 160@secure_function 161def execline(scope, data): 162 """ 163 Like exec(), but appends a newline to the command in data before sending 164 it. 165 166 :type data: string 167 :param data: The data that is sent. 168 """ 169 conn = scope.get('__connection__') 170 response = [] 171 for line in data: 172 conn.execute(line) 173 response += conn.response.split('\n')[1:] 174 scope.define(__response__=response) 175 return True 176 177 178@secure_function 179def guess_os(scope): 180 """ 181 Guesses the operating system of the connected host. 182 183 The recognition is based on the past conversation that has happened 184 on the host; Exscript looks for known patterns and maps them to specific 185 operating systems. 186 187 :rtype: string 188 :return: The operating system. 189 """ 190 conn = scope.get('__connection__') 191 return [conn.guess_os()] 192 193 194@secure_function 195def send(scope, data): 196 """ 197 Like exec(), but does not wait for a response of the remote host after 198 sending the command. 199 200 :type data: string 201 :param data: The data that is sent. 202 """ 203 conn = scope.get('__connection__') 204 for line in data: 205 conn.send(line) 206 return True 207 208 209@secure_function 210def sendline(scope, data): 211 """ 212 Like execline(), but does not wait for a response of the remote host after 213 sending the command. 214 215 :type data: string 216 :param data: The data that is sent. 217 """ 218 conn = scope.get('__connection__') 219 for line in data: 220 conn.send(line + '\r') 221 return True 222 223 224@secure_function 225def wait_for(scope, prompt): 226 """ 227 Waits until the response of the remote host contains the given pattern. 228 229 :type prompt: regex 230 :param prompt: The prompt pattern. 231 """ 232 conn = scope.get('__connection__') 233 conn.expect(prompt) 234 scope.define(__response__=conn.response) 235 return True 236 237 238@secure_function 239def set_prompt(scope, prompt=None): 240 """ 241 Defines the pattern that is recognized at any future time when Exscript 242 needs to wait for a prompt. 243 In other words, whenever Exscript waits for a prompt, it searches the 244 response of the host for the given pattern and continues as soon as the 245 pattern is found. 246 247 Exscript waits for a prompt whenever it sends a command (unless the send() 248 method was used). set_prompt() redefines as to what is recognized as a 249 prompt. 250 251 :type prompt: regex 252 :param prompt: The prompt pattern. 253 """ 254 conn = scope.get('__connection__') 255 conn.set_prompt(prompt) 256 return True 257 258 259@secure_function 260def set_error(scope, error_re=None): 261 """ 262 Defines a pattern that, whenever detected in the response of the remote 263 host, causes an error to be raised. 264 265 In other words, whenever Exscript waits for a prompt, it searches the 266 response of the host for the given pattern and raises an error if the 267 pattern is found. 268 269 :type error_re: regex 270 :param error_re: The error pattern. 271 """ 272 conn = scope.get('__connection__') 273 conn.set_error_prompt(error_re) 274 return True 275 276 277@secure_function 278def set_timeout(scope, timeout): 279 """ 280 Defines the time after which Exscript fails if it does not receive a 281 prompt from the remote host. 282 283 :type timeout: int 284 :param timeout: The timeout in seconds. 285 """ 286 conn = scope.get('__connection__') 287 conn.set_timeout(int(timeout[0])) 288 return True 289