1 /***************************************************************************
2 ksshprocess.h - description
4 begin : Tue Jul 31 2001
5 copyright : (C) 2001 by Lucas Fisher
6 email : ljfisher@purdue.edu
7 ***************************************************************************/
9 /***************************************************************************
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
16 ***************************************************************************/
21 #include <sys/types.h>
35 * Provides version independent access to ssh. Currently supported
36 * versions of SSH are:
41 * Commercial SSH 3.0.0
42 * Other versions of OpenSSH and commercial SSH will probably work also.
44 * To setup a SSH connection first create a list of options to use and tell
45 * KSshProcess about your options. Then start the ssh connection. Once the
46 * connection is setup use the stdin, stdout, stderr, and pty file descriptors
47 * to communicate with ssh. For a detailed example of how to use, see
48 * ksshprocesstest.cpp.
50 * @author Lucas Fisher
52 * Example: Connect to ssh server on localhost
53 * KSshProcess::SshOpt opt;
54 * KSshProcess::SshOptList options;
56 * opt.opt = KSshProcess::SSH_HOST;
57 * opt.str = "localhost";
58 * options.append(opt);
60 * opt.opt = KSshProcess::SSH_USERNAME;
62 * options.append(opt);
65 * if( !ssh.setOptions(options) ) {
66 * int err = ssh.error();
73 * while( !ssh.connect() ) {
74 * err = ssh.error(errMsg);
77 * case KSshProcess::ERR_NEW_HOST_KEY:
78 * case KSshProcess::ERR_DIFF_HOST_KEY:
79 * // ask user to accept key
80 * if( acceptHostKey ) {
81 * ssh.acceptKey(true);
85 * case KSshProcess::ERR_NEED_PASSWORD:
86 * // ask user for password
87 * ssh.password(userPassword);
90 * case KSshProcess::ERR_NEED_KEY_PASSPHRASE:
91 * // ask user for their key passphrase
92 * ssh.keyPassphrase(keyPassphrase);
96 * // somethings wrong, alert user
100 * // We have an open ssh connection to localhost
109 * Stores SSH options for use with KSshProcess.
111 * SSH options are configured much like UDS entries.
112 * Each option is assigned a constant and a string, bool,
113 * or number is assigned based on the option.
115 * @author Lucas Fisher (ljfisher@iastate.edu)
126 * List of SshOptions and associated iterators
128 typedef QList
<SshOpt
> SshOptList
;
129 typedef QList
<SshOpt
>::Iterator SshOptListIterator
;
130 typedef QList
<SshOpt
>::ConstIterator SshOptListConstIterator
;
133 * Ssh versions supported by KSshProcess. Subject to change
146 * SSH options supported by KSshProcess. Set SshOpt::opt to one of these
149 // we cannot do this like UDSAtomType (ORing the type with the name) because
150 // we have too many options for ssh and not enough bits.
153 * Request server to invoke subsystem. (str)
157 * Connect to port on the server. (num)
161 * Connect to host. (str)
165 * connect using this username. (str)
169 * connect using this password. (str)
173 * connect using this version of the SSH protocol. num == 1 or 2
177 * whether to forward X11 connections. (boolean)
181 * whether to do agent forwarding. (boolean)
185 * use as escape character. 0 for none (num)
189 * command for ssh to perform once it is connected (str)
193 * Set ssh verbosity. This may be added multiple times. It may also cause KSSHProcess
194 * to fail since we don't understand all the debug messages.
198 * Set a ssh option as one would find in the ssh_config file
199 * The str member should be set to 'optName value'
203 * Set some other option not supported by KSSHProcess. The option should
204 * be specified in the str member of SshOpt. Careful with this since
205 * not all versions of SSH support the same options.
208 SSH_OPT_MAX
// always last
209 }; // that's all for now
212 * Errors that KSshProcess can encounter. When a member function returns
213 * false, call error() to retrieve one of these error codes.
217 * Don't recognize the ssh version
221 * Cannot lauch ssh client
225 * Interaction with the ssh client failed. This happens when we can't
226 * find the password prompt or something similar
230 * Arguments for both a remotely executed subsystem and command were provide.
231 * Only one or the other may be used
233 ERR_CMD_SUBSYS_CONFLICT
,
235 * No password was supplied
239 * No passphrase was supplied.
243 * No usename was supplied
247 * Timed out waiting for a response from ssh or the server
251 * Internal error, probably from a system call
255 * ssh was disconnect from the host
259 * No ssh options have been set. Call setArgs() before calling connect.
263 * A host key was received from an unknown host.
264 * Call connect() with the acceptHostKey argument to accept the key.
268 * A host key different from what is stored in the user's known_hosts file
269 * has be received. This is an indication of an attack
273 * A new or different host key was rejected by the caller. The ssh
274 * connection was terminated and the ssh process killed.
276 ERR_HOST_KEY_REJECTED
,
278 * An invalid option was found in the SSH option list
282 * SSH accepted host key without prompting user.
286 * Authentication failed
290 * Authentication failed because a new host key was detected and
291 * SSH is configured with strict host key checking enabled.
293 ERR_AUTH_FAILED_NEW_KEY
,
295 * Authentication failed because a changed host key was detected and
296 * SSH is configured with strict host key checking enabled.
298 ERR_AUTH_FAILED_DIFF_KEY
,
300 * The remote host closed the connection for unknown reasons.
302 ERR_CLOSED_BY_REMOTE_HOST
,
304 * We have no idea what happened
308 * The connect state machine entered an invalid state.
315 * Initialize a SSH process using the first SSH binary found in the PATH
320 * Initialize a SSH process using the specified SSH binary.
321 * @param pathToSsh The fully qualified path name of the ssh binary
322 * KSshProcess should use to setup a SSH connection.
324 KSshProcess(QString pathToSsh
);
328 * Set the ssh binary KSshProcess should use. This will only affect the
329 * next ssh connection attempt using this instance.
331 * @param pathToSsh Full path to the ssh binary.
333 * @return True if the ssh binary is found and KSshProcess
334 * recognizes the version.
337 bool setSshPath(QString pathToSsh
);
340 * Get the ssh version.
342 * @return The ssh version or -1 if KSshProcess does not recognize
343 * the ssh version. The returned value corresponds to the
344 * member of the SshVersion enum.
346 SshVersion
version();
349 * Get a string describing the ssh version
351 * @return A string describing the ssh version recognized by KSshProcess
353 //QString versionStr();
356 * Get the last error encountered by KSshProcess.
358 * @param msg Set to the error message, if any, outputted by ssh when it is run.
360 * @return The error number. See SshError for descriptions.
362 int error(QString
& msg
);
365 * Get the last error encountered by KSshProcess.
366 * @return The error number. See SshError for descriptions.
368 int error() { return mError
; }
370 QString
errorMsg() { return mErrorMsg
; }
373 * Send a signal to the ssh process. Do not use this to end the
374 * ssh connection as it will not correctly reset the internal
375 * state of the KSshProcess object. Use KSshProcess::disconnect()
378 * @param signal The signal to send to the ssh process. See 'kill -l'
379 * for a list of possible signals.
380 * The default signal is SIGKILL which kills ssh.
383 void kill(int signal
= SIGKILL
);
386 * The pid of the ssh process started by this instance of KSshProcess.
387 * Only valid if KSshProcess::running() returns true;
389 * @return The pid of the running ssh process.
391 int pid() { return ssh
.pid(); }
394 * Whether a ssh connection has been established with a
395 * remote host. A establish connection means ssh has successfully
396 * authenticated with the remote host and user data can be transfered
397 * between the local and remote host. This cannot return
398 * true unless the most recent call to KSshProccess::connect() returned true.
400 * @return True if a ssh connection has been established with a remote
401 * host. False otherwise.
403 bool connected() { return mConnected
; }
406 * Whether a ssh process is currently running. This only indicates
407 * if a ssh process has been started and is still running. It does not
408 * tell if authentication has been successful. This may return true
409 * even if the most recent call to KSshProcess::connect() returned false.
411 * @return True if a ssh process started by this instance of KSshProcess
412 * is running. False otherwise.
414 bool running() { return mRunning
; }
417 * Print the command line arguments ssh is run with using kDebug.
422 * Set the SSH options.
423 * This must be called before connect(). See SshOptType for a list of
424 * supported ssh options. The required options are SSH_USERNAME
427 * To reset the saved options, just recall setOptions() again with
428 * a different options list.
430 * @param opts A list of SshOpt objects specifying the ssh options.
432 * @return True if all options are valid. False if unrecognized options
433 * or a required option is missing. Call error()
437 bool setOptions(const SshOptList
& opts
);
440 * Create a ssh connection based on the options provided by setOptions().
441 * Sets one of the following error codes on failure:
443 * <li>ERR_NO_OPTIONS</li>
444 * <li>ERR_CANNOT_LAUNCH</li>
445 * <li>ERR_INVALID_STATE</li>
446 * <li>ERR_NEED_PASSWD</li>
447 * <li>ERR_AUTH_FAILED</li>
448 * <li>ERR_NEW_HOST_KEY</li>
449 * <li>ERR_KEY_ACCEPTED</li>
450 * <li>ERR_DIFF_HOST_KEY</li>
451 * <li>ERR_INTERNAL</li>
452 * <li>ERR_INTERACT</li>
455 * @param acceptHostKey When true KSshProcess will automatically accept
456 * unrecognized or changed host keys.
458 * @return True if the ssh connection is successful. False if the connection
459 * fails. Call error() to get the reason for the failure.
465 * Disconnect ssh from the host. This kills the ssh process and
466 * resets the internal state of this KSshProcess object. After a
467 * disconnect, the same KSshProcess can be used to connect to a
473 * Call to respond to a ERR_NEW_HOST_KEY or ERR_DIFF_HOST_KEY error.
475 * @param accept True to accept the host key, false to not accept the
476 * host key and kill ssh.
479 void acceptHostKey(bool accept
);
482 * Call to respond to a ERR_NEED_PASSWD or ERR_NEED_PASSPHRASE error.
484 * @param password The user password to give ssh.
486 void setPassword(QString password
);
489 * Access to standard in and out of the ssh process.
491 * @return The file description for stdin and stdout of the ssh process.
493 int stdioFd() { return ssh
.stdioFd(); }
496 * Access to standard error of the ssh process.
498 * @return The file descriptior for stderr of the ssh process.
500 int stderrFd() { return ssh
.stderrFd(); }
503 * Access the pty to which the ssh process is attached.
505 * @return The file descriptor of pty to which ssh is attached.
508 int pty() { return ssh
.fd(); }
510 KProcess
*pty() { return ssh
.fd(); }
514 * Path to the ssh binary.
519 * SSH version. This is an index into the supported SSH
520 * versions array, and the various messages arrays.
525 * User's password. Zero this out when it is no longer needed.
535 * Name of host we are connecting to.
540 * Accept new or changed host keys if true.
545 * Flag to tell use if we have an open, authenticated ssh
551 * Flag to tell us if we have started a ssh process, we use this
552 * to make sure we kill ssh before going away.
557 * Save any key fingerprint msg from ssh so we can present
560 QString mKeyFingerprint
;
563 * The location of the known host key file. We grab this from
564 * any error messages ssh prints out.
566 QString mKnownHostsFile
;
569 * The state of our connect state machine.
574 * Port on on which the target ssh server is listening.
579 * The last error number encountered. This is only valid for the
585 * An error message that corresponds to the error number set in
591 * Interface to the SSH process we ceate. Handles communication
592 * to and from the SSH process using stdin, stdout, stderr, and
598 * List of arguments we start SSH with.
604 * Handler to clean up when ssh process terminates.
606 static void SIGCHLD_handler(int signo
);
607 void installSignalHandlers();
608 void removeSignalHandlers();
612 static QRegExp versionStrs
[];
613 static const char * const passwordPrompt
[];
614 static const char * const passphrasePrompt
[];
615 static const char * const authSuccessMsg
[];
616 static const char * const authFailedMsg
[];
617 static QRegExp hostKeyMissingMsg
[];
618 static const char * const hostKeyChangedMsg
[];
619 static const char * const continuePrompt
[];
620 static const char * const hostKeyAcceptedMsg
[];
621 static const char * const tryAgainMsg
[];
622 static QRegExp hostKeyVerifyFailedMsg
[];
623 static const char * const connectionClosedMsg
[];
624 static const char * const changeHostKeyOnDiskPrompt
[];
625 static QRegExp keyFingerprintMsg
[];
626 static QRegExp knownHostsFileMsg
[];