delay a few things on startup, such as setting the visibility mode, which ensures...
[personal-kdebase.git] / runtime / kioslave / sftp / ksshprocess.h
blob5964e9ffc6dc908c841f506d45dc7358dbdbae4f
1 /***************************************************************************
2 ksshprocess.h - description
3 -------------------
4 begin : Tue Jul 31 2001
5 copyright : (C) 2001 by Lucas Fisher
6 email : ljfisher@purdue.edu
7 ***************************************************************************/
9 /***************************************************************************
10 * *
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. *
15 * *
16 ***************************************************************************/
18 #ifndef KSSHPROCESS_H
19 #define KSSHPROCESS_H
21 #include <sys/types.h>
22 #include <sys/wait.h>
23 #include <signal.h>
24 #include <unistd.h>
28 #include <kdebug.h>
30 #include "process.h"
32 #define KSSHPROC 7120
34 /**
35 * Provides version independent access to ssh. Currently supported
36 * versions of SSH are:
37 * OpenSSH 2.9p1
38 * OpenSSH 2.9p2
39 * OpenSSH 3.0
40 * OpenSSH 3.1
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;
61 * opt.str = "me";
62 * options.append(opt);
64 * KSshProcess ssh;
65 * if( !ssh.setOptions(options) ) {
66 * int err = ssh.error();
67 * // process error
68 * return false;
69 * }
71 * int err;
72 * QString errMsg;
73 * while( !ssh.connect() ) {
74 * err = ssh.error(errMsg);
76 * switch( err ) {
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);
82 * }
83 * break;
85 * case KSshProcess::ERR_NEED_PASSWORD:
86 * // ask user for password
87 * ssh.password(userPassword);
88 * break;
90 * case KSshProcess::ERR_NEED_KEY_PASSPHRASE:
91 * // ask user for their key passphrase
92 * ssh.keyPassphrase(keyPassphrase);
93 * break;
95 * default:
96 * // somethings wrong, alert user
97 * return;
98 * }
99 * }
100 * // We have an open ssh connection to localhost
104 class KSshProcess {
105 public:
107 * SSH Option
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)
117 class SshOpt {
118 public:
119 quint32 opt;
120 QString str;
121 qint32 num;
122 bool boolean;
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
134 * at any time.
136 enum SshVersion {
137 OPENSSH_3_6,
138 OPENSSH,
139 SSH,
140 PLINK,
141 SSH_VER_MAX,
142 UNKNOWN_VER
146 * SSH options supported by KSshProcess. Set SshOpt::opt to one of these
147 * values.
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.
151 enum SshOptType {
153 * Request server to invoke subsystem. (str)
155 SSH_SUBSYSTEM,
157 * Connect to port on the server. (num)
159 SSH_PORT,
161 * Connect to host. (str)
163 SSH_HOST,
165 * connect using this username. (str)
167 SSH_USERNAME,
168 /**
169 * connect using this password. (str)
171 SSH_PASSWD,
173 * connect using this version of the SSH protocol. num == 1 or 2
175 SSH_PROTOCOL,
177 * whether to forward X11 connections. (boolean)
179 SSH_FORWARDX11,
181 * whether to do agent forwarding. (boolean)
183 SSH_FORWARDAGENT,
185 * use as escape character. 0 for none (num)
187 SSH_ESCAPE_CHAR,
189 * command for ssh to perform once it is connected (str)
191 SSH_COMMAND,
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.
196 SSH_VERBOSE,
198 * Set a ssh option as one would find in the ssh_config file
199 * The str member should be set to 'optName value'
201 SSH_OPTION,
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.
207 SSH_OTHER,
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.
215 enum SshError {
217 * Don't recognize the ssh version
219 ERR_UNKNOWN_VERSION,
221 * Cannot lauch ssh client
223 ERR_CANNOT_LAUNCH,
225 * Interaction with the ssh client failed. This happens when we can't
226 * find the password prompt or something similar
228 ERR_INTERACT,
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
237 ERR_NEED_PASSWD,
239 * No passphrase was supplied.
241 ERR_NEED_PASSPHRASE,
243 * No usename was supplied
245 ERR_NEED_USERNAME,
247 * Timed out waiting for a response from ssh or the server
249 ERR_TIMED_OUT,
251 * Internal error, probably from a system call
253 ERR_INTERNAL,
255 * ssh was disconnect from the host
257 ERR_DISCONNECTED,
259 * No ssh options have been set. Call setArgs() before calling connect.
261 ERR_NO_OPTIONS,
263 * A host key was received from an unknown host.
264 * Call connect() with the acceptHostKey argument to accept the key.
266 ERR_NEW_HOST_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
271 ERR_DIFF_HOST_KEY,
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
280 ERR_INVALID_OPT,
282 * SSH accepted host key without prompting user.
284 ERR_ACCEPTED_KEY,
286 * Authentication failed
288 ERR_AUTH_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
306 ERR_UNKNOWN,
308 * The connect state machine entered an invalid state.
310 ERR_INVALID_STATE,
311 ERR_MAX
315 * Initialize a SSH process using the first SSH binary found in the PATH
317 KSshProcess();
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);
325 ~KSshProcess();
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()
376 * instead.
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.
419 void printArgs();
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
425 * and SSH_HOST.
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()
434 * for details.
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:
442 * <ul>
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>
453 * </ul>
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.
461 bool connect();
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
468 * host.
470 void disconnect();
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.
507 #ifndef Q_WS_WIN
508 int pty() { return ssh.fd(); }
509 #else
510 KProcess *pty() { return ssh.fd(); }
511 #endif
512 private:
514 * Path to the ssh binary.
516 QString mSshPath;
519 * SSH version. This is an index into the supported SSH
520 * versions array, and the various messages arrays.
522 SshVersion mVersion;
525 * User's password. Zero this out when it is no longer needed.
527 QString mPassword;
530 * User's username.
532 QString mUsername;
535 * Name of host we are connecting to.
537 QString mHost;
540 * Accept new or changed host keys if true.
542 bool mAcceptHostKey;
545 * Flag to tell use if we have an open, authenticated ssh
546 * session going.
548 bool mConnected;
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.
554 bool mRunning;
557 * Save any key fingerprint msg from ssh so we can present
558 * it to the caller.
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.
571 int mConnectState;
574 * Port on on which the target ssh server is listening.
576 int mPort;
579 * The last error number encountered. This is only valid for the
580 * last error.
582 SshError mError;
585 * An error message that corresponds to the error number set in
586 * mError. Optional.
588 QString mErrorMsg;
591 * Interface to the SSH process we ceate. Handles communication
592 * to and from the SSH process using stdin, stdout, stderr, and
593 * pty.
595 MyPtyProcess ssh;
598 * List of arguments we start SSH with.
600 QCStringList mArgs;
601 void init();
604 * Handler to clean up when ssh process terminates.
606 static void SIGCHLD_handler(int signo);
607 void installSignalHandlers();
608 void removeSignalHandlers();
610 QString getLine();
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[];
628 #endif