options.c   options.c 
skipping to change at line 25 skipping to change at line 25
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILI TY * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILI TY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details. * License for more details.
* *
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to * along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA. * MA 02111-1307, USA.
*/ */
#include "config.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
#include <string.h> #include <string.h>
#ifndef _WIN32 #ifndef _WIN32
#include <pwd.h> #include <pwd.h>
#else
#include <winsock2.h>
#endif #endif
#include <sys/types.h> #include <sys/types.h>
#include "libssh/priv.h" #include "libssh/priv.h"
#include "libssh/session.h"
/** \defgroup ssh_options SSH Options #include "libssh/misc.h"
* \brief options settings for a new SSH session #ifdef WITH_SERVER
*/ #include "libssh/server.h"
/** \addtogroup ssh_options
* @{ */
/** This structure is freed automaticaly by ssh_disconnect()
* when you use it. \n
* It can be used by only one ssh_connect(), not more.\n
* also by default, ssh1 support is not allowed
*
* \brief initializes a new option structure
* \returns an empty intialized option structure.
* \see ssh_options_getopt()
*/
SSH_OPTIONS *ssh_options_new(void) {
SSH_OPTIONS *option;
option = malloc(sizeof(SSH_OPTIONS));
if (option == NULL) {
return NULL;
}
memset(option,0,sizeof(SSH_OPTIONS));
option->port=22; /* set the default port */
option->fd=-1;
option->ssh2allowed=1;
#ifdef WITH_SSH1
option->ssh1allowed=1;
#else
option->ssh1allowed=0;
#endif #endif
option->bindport=22;
return option;
}
/** /**
* @brief Set port to connect or to bind for a connection. * @brief Duplicate the options of a session structure.
*
* @param opt The options structure to use.
*
* @param port The port to connect or to bind.
*
* @return 0 on success, < 0 on error.
*/
int ssh_options_set_port(SSH_OPTIONS *opt, unsigned int port) {
if (opt == NULL) {
return -1;
}
opt->port = port & 0xffff;
opt->bindport = port & 0xffff;
return 0;
}
/**
* @brief Duplicate an option structure.
* *
* If you make several sessions with the same options this is useful. You * If you make several sessions with the same options this is useful. You
* cannot use twice the same option structure in ssh_session_connect. * cannot use twice the same option structure in ssh_session_connect.
* *
* @param opt Option structure to copy. * @param opt Option structure to copy.
* *
* @returns New copied option structure, NULL on error. * @returns New copied option structure, NULL on error.
* *
* @see ssh_session_connect() * @see ssh_session_connect()
*/ */
SSH_OPTIONS *ssh_options_copy(SSH_OPTIONS *opt) { int ssh_options_copy(ssh_session src, ssh_session *dest) {
SSH_OPTIONS *new = NULL; ssh_session new;
int i; int i;
if (opt == NULL) { if (src == NULL || dest == NULL || *dest == NULL) {
return NULL; return -1;
} }
new = ssh_options_new(); new = *dest;
if (new == NULL) {
return NULL;
}
if (opt->username) { if (src->username) {
new->username = strdup(opt->username); new->username = strdup(src->username);
if (new->username == NULL) { if (new->username == NULL) {
goto err; return -1;
}
}
if (opt->host) {
new->host = strdup(opt->host);
if (new->host == NULL) {
goto err;
} }
} }
if (opt->bindaddr) {
new->host = strdup(opt->bindaddr); if (src->host) {
new->host = strdup(src->host);
if (new->host == NULL) { if (new->host == NULL) {
goto err; return -1;
} }
} }
if (opt->identity) {
new->identity=strdup(opt->identity); if (src->identity) {
new->identity = strdup(src->identity);
if (new->identity == NULL) { if (new->identity == NULL) {
return NULL; return -1;
}
}
if (opt->ssh_dir) {
new->ssh_dir = strdup(opt->ssh_dir);
if (new->ssh_dir == NULL) {
goto err;
}
}
if (opt->known_hosts_file) {
new->known_hosts_file = strdup(opt->known_hosts_file);
if (new->known_hosts_file == NULL) {
goto err;
} }
} }
if (opt->dsakey) {
new->dsakey = strdup(opt->dsakey); if (src->sshdir) {
if (new->dsakey == NULL) { new->sshdir = strdup(src->sshdir);
goto err; if (new->sshdir == NULL) {
return -1;
} }
} }
if (opt->rsakey) {
new->rsakey = strdup(opt->rsakey); if (src->knownhosts) {
if (new->rsakey == NULL) { new->knownhosts = strdup(src->knownhosts);
goto err; if (new->knownhosts == NULL) {
return -1;
} }
} }
for (i = 0; i < 10; ++i) { for (i = 0; i < 10; ++i) {
if (opt->wanted_methods[i]) { if (src->wanted_methods[i]) {
new->wanted_methods[i] = strdup(opt->wanted_methods[i]); new->wanted_methods[i] = strdup(src->wanted_methods[i]);
if (new->wanted_methods[i] == NULL) { if (new->wanted_methods[i] == NULL) {
goto err; return -1;
} }
} }
} }
new->fd = opt->fd; new->fd = src->fd;
new->port = opt->port; new->port = src->port;
new->auth_function = opt->auth_function; new->callbacks = src->callbacks;
new->auth_userdata = opt->auth_userdata; new->timeout = src->timeout;
new->connect_status_function = opt->connect_status_function; new->timeout_usec = src->timeout_usec;
new->connect_status_arg = opt->connect_status_arg; new->ssh2 = src->ssh2;
new->timeout = opt->timeout; new->ssh1 = src->ssh1;
new->timeout_usec = opt->timeout_usec; new->log_verbosity = src->log_verbosity;
new->ssh2allowed = opt->ssh2allowed;
new->ssh1allowed = opt->ssh1allowed;
new->log_function = opt->log_function;
new->log_verbosity = opt->log_verbosity;
return new; return 0;
err:
ssh_options_free(new);
return NULL;
} }
/** #ifndef _WIN32
* @brief Frees an option structure. static char *get_username_from_uid(ssh_session session, uid_t uid){
* struct passwd *pwd = NULL;
* @param opt Option structure to free. char *name;
*/
void ssh_options_free(SSH_OPTIONS *opt) {
int i;
if (opt == NULL) { pwd = getpwuid(uid);
return;
}
/* if (pwd == NULL) {
* We don't touch the banner. If the implementation ssh_set_error(session, SSH_FATAL, "uid %d doesn't exist !", uid);
* did use it, they have to free it return NULL;
*/
SAFE_FREE(opt->username);
SAFE_FREE(opt->host);
SAFE_FREE(opt->identity);
SAFE_FREE(opt->bindaddr);
SAFE_FREE(opt->ssh_dir);
SAFE_FREE(opt->known_hosts_file);
SAFE_FREE(opt->dsakey);
SAFE_FREE(opt->rsakey);
for (i = 0; i < 10; i++) {
if (opt->wanted_methods[i]) {
free(opt->wanted_methods[i]);
} }
}
ZERO_STRUCTP(opt);
SAFE_FREE(opt);
}
/** name = strdup(pwd->pw_name);
* @brief Set destination hostname
* if (name == NULL) {
* @param opt The option structure to use. ssh_set_error_oom(session);
* return NULL;
* @param hostname The host name to connect. }
*
* @return 0 on succes, < 0 on error.
*/
int ssh_options_set_host(SSH_OPTIONS *opt, const char *hostname){
char *h;
char *p;
if (opt == NULL || hostname == NULL) { return name;
}
#endif
int ssh_options_set_algo(ssh_session session, int algo,
const char *list) {
if (!verify_existing_algo(algo, list)) {
ssh_set_error(session, SSH_REQUEST_DENIED,
"Setting method: no algorithm for method \"%s\" (%s)\n",
ssh_kex_nums[algo], list);
return -1; return -1;
} }
h = strdup(hostname); SAFE_FREE(session->wanted_methods[algo]);
if (h == NULL) { session->wanted_methods[algo] = strdup(list);
if (session->wanted_methods[algo] == NULL) {
ssh_set_error_oom(session);
return -1; return -1;
} }
p = strchr(h, '@');
SAFE_FREE(opt->host); return 0;
}
if (p) { char *dir_expand_dup(ssh_session session, const char *value, int allowsshdi
*p = '\0'; r) {
opt->host = strdup(p + 1); char *new;
if (opt->host == NULL) {
SAFE_FREE(h);
return -1;
}
SAFE_FREE(opt->username); if (value[0] == '~' && value[1] == '/') {
opt->username = strdup(h); char *homedir = ssh_get_user_home_dir();
SAFE_FREE(h); size_t lv, lh;
if (opt->username == NULL) {
return -1; if (homedir == NULL) {
return NULL;
} }
} else { lv = strlen(value + 1);
opt->host = h; lh = strlen(homedir);
}
return 0; new = malloc(lv + lh + 1);
if (new == NULL) {
ssh_set_error_oom(session);
SAFE_FREE(homedir);
return NULL;
}
memcpy(new, homedir, lh);
SAFE_FREE(homedir);
memcpy(new + lh, value + 1, lv + 1);
return new;
}
if (allowsshdir && strncmp(value, "SSH_DIR/", 8) == 0) {
size_t lv, ls;
if (session->sshdir == NULL) {
if (ssh_options_set(session, SSH_OPTIONS_SSH_DIR, NU
LL) < 0)
return NULL;
}
value += 7;
lv = strlen(value);
ls = strlen(session->sshdir);
new = malloc(lv + ls + 1);
if (new == NULL) {
ssh_set_error_oom(session);
return NULL;
}
memcpy(new, session->sshdir, ls);
memcpy(new + ls, value, lv + 1);
return new;
}
new = strdup(value);
if (new == NULL) {
ssh_set_error_oom(session);
return NULL;
}
return new;
} }
/** /**
* @brief Set the username for authentication * @brief This function can set all possible ssh options.
*
* @param opt The options structure to use.
* *
* @param username The username to authenticate. * @param session An allocated ssh option structure.
* *
* @return 0 on success, -1 on error. * @param type The option type to set. This could be one of the
* following:
* *
* @bug this should not be set at options time * SSH_OPTIONS_HOST:
*/ * The hostname or ip address to connect to (string)
int ssh_options_set_username(SSH_OPTIONS *opt, const char *username) { .
if (opt == NULL || username == NULL) {
return -1;
}
SAFE_FREE(opt->username);
opt->username = strdup(username);
if (opt->username == NULL) {
return -1;
}
return 0;
}
/**
* @brief Set a file descriptor for connection.
* *
* If you wish to open the socket yourself for a reason or another, set the * SSH_OPTIONS_PORT:
* file descriptor. Don't forget to use ssh_option_set_hostname() as the * The port to connect to (integer).
* hostname is used as a key in the known_host mechanism.
* *
* @param opt The options structure to use. * SSH_OPTIONS_PORT_STR:
* The port to connect to (string).
* *
* @param fd An opened file descriptor to use. * SSH_OPTIONS_FD:
* The file descriptor to use (socket_t).
* *
* @return 0 on success, < 0 on error. * If you wish to open the socket yourself for a rea
*/ son
int ssh_options_set_fd(SSH_OPTIONS *opt, socket_t fd) { * or another, set the file descriptor. Don't forget
if (opt == NULL) { to
return -1; * set the hostname as the hostname is used as a key
} in
opt->fd = fd; * the known_host mechanism.
return 0;
}
/**
* @brief Set the local address and port binding.
* *
* In case your client has multiple IP adresses, select the local address a * SSH_OPTIONS_USER:
nd * The username for authentication (string).
* port to use for the socket.\n
* If the address or port is not bindable, it may be impossible to connect.
* *
* @param opt The options structure to use. * If the value is NULL, the username is set to the
* default username.
* *
* @param bindaddr The bind address in form of hostname or ip address. * SSH_OPTIONS_SSH_DIR:
* Set the ssh directory (format string).
* *
* @param port The port number to bind. * If the value is NULL, the directory is set to the
* default ssh directory.
* *
* @return 0 on success, < 0 on error. * The ssh directory is used for files like known_ho
*/ sts
int ssh_options_set_bind(SSH_OPTIONS *opt, const char *bindaddr, int port) * and identity (private and public key). It may inc
{ lude
if (opt == NULL || bindaddr == NULL) { * "%s" which will be replaced by the user home
return -1; * directory.
}
SAFE_FREE(opt->bindaddr);
opt->bindaddr = strdup(bindaddr);
if (opt->bindaddr == NULL) {
return -1;
}
opt->bindport = port;
return 0;
}
/**
* @brief Set the ssh directory.
* *
* The ssh directory is used for files like known_hosts and identity (publi * SSH_OPTIONS_KNOWNHOSTS:
c * Set the known hosts file name (format string).
* and private keys)
* *
* @param opt The options structure to use. * If the value is NULL, the directory is set to the
* default known hosts file, normally ~/.ssh/known_h
osts.
* *
* @param dir The directory to set. It may include "%s" which wil * The known hosts file is used to certify remote ho
l be sts
* replaced by the user home directory. * are genuine. It may include "%s" which will be
* replaced by the user home directory.
* *
* @return 0 on success, < 0 on error. * SSH_OPTIONS_IDENTITY:
* Set the identity file name (format string).
* *
* @see ssh_options_set_user_home_dir() * By default identity, id_dsa and id_rsa are checke
*/ d.
int ssh_options_set_ssh_dir(SSH_OPTIONS *opt, const char *dir) {
char buffer[1024] = {0};
if (opt == NULL || dir == NULL) {
return -1;
}
snprintf(buffer, 1024, dir, ssh_get_user_home_dir());
SAFE_FREE(opt->ssh_dir);
opt->ssh_dir = strdup(buffer);
if (opt->ssh_dir == NULL) {
return -1;
}
return 0;
}
/**
* @brief Set the known hosts file name.
* *
* The known hosts file is used to certify remote hosts are genuine. * The identity file used authenticate with public k
ey.
* It may include "%s" which will be replaced by the
* user home directory.
* *
* @param opt The options structure to use. * SSH_OPTIONS_TIMEOUT:
* Set a timeout for the connection in seconds (inte
ger).
* *
* @param dir The path to the file including its name. "%s" will * SSH_OPTIONS_TIMEOUT_USEC:
be * Set a timeout for the connection in micro seconds
* substitued with the user home directory. * (integer).
* *
* @return 0 on success, < 0 on error. * SSH_OPTIONS_SSH1:
* Allow or deny the connection to SSH1 servers
* (integer).
* *
* @see ssh_options_set_user_home_dir() * SSH_OPTIONS_SSH2:
*/ * Allow or deny the connection to SSH2 servers
int ssh_options_set_known_hosts_file(SSH_OPTIONS *opt, const char *dir){ * (integer).
char buffer[1024] = {0};
if (opt == NULL || dir == NULL) {
return -1;
}
snprintf(buffer, 1024, dir, ssh_get_user_home_dir());
SAFE_FREE(opt->known_hosts_file);
opt->known_hosts_file = strdup(buffer);
if (opt->known_hosts_file == NULL) {
return -1;
}
return 0;
}
/**
* @brief Set the identity file name.
* *
* The identity file is used authenticate with public key. * SSH_OPTIONS_LOG_VERBOSITY:
* Set the session logging verbosity (integer).
* *
* @param opt The options structure to use. * The verbosity of the messages. Every log smaller
or
* equal to verbosity will be shown.
* SSH_LOG_NOLOG: No logging
* SSH_LOG_RARE: Rare conditions or warnings
* SSH_LOG_ENTRY: API-accessible entrypoints
* SSH_LOG_PACKET: Packet id and size
* SSH_LOG_FUNCTIONS: Function entering and leavin
g
* *
* @param identity The path to the file including its name. "%s" will * SSH_OPTIONS_LOG_VERBOSITY_STR:
be * Set the session logging verbosity (string).
* substitued with the user home directory.
* *
* @return 0 on success, < 0 on error. * The verbosity of the messages. Every log smaller
or
* equal to verbosity will be shown.
* SSH_LOG_NOLOG: No logging
* SSH_LOG_RARE: Rare conditions or warnings
* SSH_LOG_ENTRY: API-accessible entrypoints
* SSH_LOG_PACKET: Packet id and size
* SSH_LOG_FUNCTIONS: Function entering and leavin
g
* *
* @see ssh_options_set_user_home_dir() * See the corresponding numbers in libssh.h.
*/
int ssh_options_set_identity(SSH_OPTIONS *opt, const char *identity){
char buffer[1024] = {0};
if (opt == NULL || identity == NULL) {
return -1;
}
snprintf(buffer, 1024, identity, ssh_get_user_home_dir());
SAFE_FREE(opt->identity);
opt->identity = strdup(buffer);
if (opt->identity == NULL) {
return -1;
}
return 0;
}
/**
* @brief Set the path to the dsa ssh host key.
* *
* @param opt The options structure to use. * SSH_OPTTIONS_AUTH_CALLBACK:
* Set a callback to use your own authentication fun
ction
* (function pointer).
* *
* @param dsakey The path to the dsa key to set. * SSH_OPTTIONS_AUTH_USERDATA:
* Set the user data passed to the authentication fu
nction
* (generic pointer).
* *
* @return 0 on success, < 0 on error. * SSH_OPTTIONS_LOG_CALLBACK:
*/ * Set a callback to use your own logging function
int ssh_options_set_dsa_server_key(SSH_OPTIONS *opt, const char *dsakey) { * (function pointer).
if (opt == NULL || dsakey == NULL) {
return -1;
}
opt->dsakey = strdup(dsakey);
if (opt->dsakey == NULL) {
return -1;
}
return 0;
}
/**
* @brief Set the path to the ssh host rsa key.
* *
* @param opt The options structure to use. * SSH_OPTTIONS_LOG_USERDATA:
* Set the user data passed to the logging function
* (generic pointer).
* *
* @param rsakey The path to the rsa key to set. * SSH_OPTTIONS_STATUS_CALLBACK:
* Set a callback to show connection status in realt
ime
* (function pointer).
* *
* @return 0 on success, < 0 on error. * fn(void *arg, float status)
*/
int ssh_options_set_rsa_server_key(SSH_OPTIONS *opt, const char *rsakey) {
if (opt == NULL || rsakey == NULL) {
return -1;
}
opt->rsakey = strdup(rsakey);
if (opt->rsakey == NULL) {
return -1;
}
return 0;
}
/**
* @brief Set the server banner sent to clients.
* *
* @param opt The options structure to use. * During ssh_connect(), libssh will call the callba
ck
* with status from 0.0 to 1.0.
* *
* @param banner A text banner to be shown. * SSH_OPTTIONS_STATUS_ARG:
* Set the status argument which should be passed to
the
* status callback (generic pointer).
* *
* @return 0 on success, < 0 on error. * SSH_OPTIONS_CIPHERS_C_S:
*/ * Set the symmetric cipher client to server (string
int ssh_options_set_banner(SSH_OPTIONS *opt, const char *banner) { ,
if (opt == NULL || banner == NULL) { * comma-separated list).
return -1;
}
SAFE_FREE(opt->banner);
opt->banner = strdup(banner);
if (opt->banner == NULL) {
return -1;
}
return 0;
}
/**
* @brief Set the algorithms to be used for cryptography and compression.
* *
* The methods are:\n * SSH_OPTIONS_CIPHERS_S_C:
* KEX_HOSTKEY (server public key type) : ssh-rsa or ssh-dss\n * Set the symmetric cipher server to client (string
* KEX_CRYPT_C_S (symmetric cipher client to server)\n ,
* KEX_CRYPT_S_C (symmetric cipher server to client)\n * comma-separated list).
* KEX_COMP_C_S (Compression client to server): zlib or none\n
* KEX_COMP_S_C (Compression server to client): zlib or none\n
* You don't have to use this function if using the default ciphers
* is okay for you\n
* in order to enable compression client to server, do\n
* @code
* ret = ssh_options_set_wanted_algos(opt,KEX_COMP_C_S,"zlib");
* @endcode
* *
* @param opt The options structure to use. * SSH_OPTIONS_COMPRESSION_C_S:
* Set the compression to use for client to server
* communication (string, "none" or "zlib").
* *
* @param algo The method which needs to be changed. * SSH_OPTIONS_COMPRESSION_S_C:
* Set the compression to use for server to client
* communication (string, "none" or "zlib").
* *
* @param list A list of algorithms to be used, in order of prefer * @param value The value to set. This is a generic pointer and the
ence * datatype which is used should be set according to t
* and separated by commas. he
* type set.
* *
* @return 0 on success, < 0 on error * @return 0 on success, < 0 on error.
*/ */
int ssh_options_set_wanted_algos(SSH_OPTIONS *opt, int algo, const char *li int ssh_options_set(ssh_session session, enum ssh_options_e type,
st) { const void *value) {
if (opt == NULL || list == NULL) { char *p, *q;
return -1; long int i;
}
if(algo > SSH_LANG_S_C || algo < 0) {
ssh_set_error(opt, SSH_REQUEST_DENIED, "algo %d out of range", algo);
return -1;
}
if ((!opt->use_nonexisting_algo) && !verify_existing_algo(algo, list)) {
ssh_set_error(opt, SSH_REQUEST_DENIED, "Setting method: no algorithm "
"for method \"%s\" (%s)\n", ssh_kex_nums[algo], list);
return -1;
}
SAFE_FREE(opt->wanted_methods[algo]); if (session == NULL) {
opt->wanted_methods[algo] = strdup(list);
if (opt->wanted_methods[algo] == NULL) {
return -1; return -1;
} }
return 0; switch (type) {
} case SSH_OPTIONS_HOST:
q = strdup(value);
if (q == NULL) {
ssh_set_error_oom(session);
return -1;
}
p = strchr(q, '@');
#ifndef _WIN32 SAFE_FREE(session->host);
static char *get_username_from_uid(SSH_OPTIONS *opt, uid_t uid){
struct passwd *pwd = NULL;
pwd = getpwuid(uid); if (p) {
*p = '\0';
session->host = strdup(p + 1);
if (session->host == NULL) {
SAFE_FREE(q);
ssh_set_error_oom(session);
return -1;
}
if (pwd == NULL) { SAFE_FREE(session->username);
ssh_set_error(opt,SSH_FATAL,"uid %d doesn't exist !",uid); session->username = strdup(q);
return NULL; SAFE_FREE(q);
} if (session->username == NULL) {
ssh_set_error_oom(session);
return -1;
}
} else {
session->host = q;
}
break;
case SSH_OPTIONS_PORT:
if (value == NULL) {
session->port = 22 & 0xffff;
} else {
int *x = (int *) value;
return strdup(pwd->pw_name); session->port = *x & 0xffff;
} }
#endif break;
case SSH_OPTIONS_PORT_STR:
if (value == NULL) {
session->port = 22 & 0xffff;
} else {
q = strdup(value);
if (q == NULL) {
ssh_set_error_oom(session);
return -1;
}
i = strtol(q, &p, 10);
if (q == p) {
SAFE_FREE(q);
}
SAFE_FREE(q);
/* this function must be called when no specific username has been asked. i session->port = i & 0xffff;
t has to guess it */ }
int ssh_options_default_username(SSH_OPTIONS *opt) { break;
char *user = NULL; case SSH_OPTIONS_USER:
SAFE_FREE(session->username);
if (value == NULL) { /* set default username */
#ifdef _WIN32
DWORD size = 0;
GetUserName(NULL, &size); //Get Size
q = malloc(size);
if (q == NULL) {
ssh_set_error_oom(session);
return -1;
}
if (GetUserName(q, &size)) {
session->username = q;
} else {
SAFE_FREE(q);
return -1;
}
#else /* _WIN32 */
q = get_username_from_uid(session, getuid());
if (q == NULL) {
return -1;
}
session->username = q;
#endif /* _WIN32 */
} else { /* username provided */
session->username = strdup(value);
if (session->username == NULL) {
ssh_set_error_oom(session);
return -1;
}
}
break;
case SSH_OPTIONS_SSH_DIR:
if (value == NULL) {
SAFE_FREE(session->sshdir);
/* TODO: why ~/.ssh/ instead of ~/.ssh ? */
session->sshdir = dir_expand_dup(session, "~/.ssh/", 0);
if (session->sshdir == NULL) {
return -1;
}
} else {
SAFE_FREE(session->sshdir);
session->sshdir = dir_expand_dup(session, value, 0);
if (session->sshdir == NULL) {
return -1;
}
}
break;
case SSH_OPTIONS_IDENTITY:
if (opt->username) { if (value == NULL) {
return 0; ssh_set_error_invalid(session, __FUNCTION__);
} return -1;
}
SAFE_FREE(session->identity);
session->identity = dir_expand_dup(session, value, 1);
if (session->identity == NULL) {
return -1;
}
break;
case SSH_OPTIONS_KNOWNHOSTS:
if (value == NULL) {
SAFE_FREE(session->knownhosts);
session->knownhosts = dir_expand_dup(session,
"SSH_DIR/known_hosts", 1);
if (session->knownhosts == NULL) {
return -1;
}
} else {
SAFE_FREE(session->knownhosts);
session->knownhosts = dir_expand_dup(session, value, 1);
if (session->knownhosts == NULL) {
return -1;
}
}
break;
case SSH_OPTIONS_TIMEOUT:
if (value == NULL) {
ssh_set_error_invalid(session, __FUNCTION__);
return -1;
} else {
long *x = (long *) value;
#ifndef _WIN32 session->timeout = *x & 0xffffffff;
user = get_username_from_uid(opt,getuid()); }
if (user) { break;
opt->username = user; case SSH_OPTIONS_TIMEOUT_USEC:
return 0; if (value == NULL) {
} ssh_set_error_invalid(session, __FUNCTION__);
#else return -1;
DWORD Size = 0; } else {
GetUserName(NULL, &Size); //Get Size long *x = (long *) value;
user = malloc(Size);
if (user == NULL) {
return -1;
}
if (GetUserName(user, &Size)) {
opt->username=user;
return 0;
} else {
SAFE_FREE(user);
}
#endif
return -1;
}
int ssh_options_default_ssh_dir(SSH_OPTIONS *opt) { session->timeout_usec = *x & 0xffffffff;
char buffer[256] = {0}; }
break;
case SSH_OPTIONS_SSH1:
if (value == NULL) {
ssh_set_error_invalid(session, __FUNCTION__);
return -1;
} else {
int *x = (int *) value;
session->ssh1 = *x;
}
break;
case SSH_OPTIONS_SSH2:
if (value == NULL) {
ssh_set_error_invalid(session, __FUNCTION__);
return -1;
} else {
int *x = (int *) value;
session->ssh2 = *x & 0xffff;
}
break;
case SSH_OPTIONS_LOG_VERBOSITY:
if (value == NULL) {
ssh_set_error_invalid(session, __FUNCTION__);
return -1;
} else {
int *x = (int *) value;
if (opt->ssh_dir) { session->log_verbosity = *x & 0xffff;
return 0; }
} break;
case SSH_OPTIONS_LOG_VERBOSITY_STR:
if (value == NULL) {
session->log_verbosity = 0 & 0xffff;
} else {
q = strdup(value);
if (q == NULL) {
ssh_set_error_oom(session);
return -1;
}
i = strtol(q, &p, 10);
if (q == p) {
SAFE_FREE(q);
}
SAFE_FREE(q);
snprintf(buffer, 256, "%s/.ssh/", ssh_get_user_home_dir()); session->log_verbosity = i & 0xffff;
opt->ssh_dir = strdup(buffer); }
if (opt->ssh_dir == NULL) { break;
return -1; case SSH_OPTIONS_CIPHERS_C_S:
if (value == NULL) {
ssh_set_error_invalid(session, __FUNCTION__);
return -1;
} else {
if (ssh_options_set_algo(session, SSH_CRYPT_C_S, value) < 0)
return -1;
}
break;
case SSH_OPTIONS_CIPHERS_S_C:
if (value == NULL) {
ssh_set_error_invalid(session, __FUNCTION__);
return -1;
} else {
if (ssh_options_set_algo(session, SSH_CRYPT_S_C, value) < 0)
return -1;
}
break;
case SSH_OPTIONS_COMPRESSION_C_S:
if (value == NULL) {
ssh_set_error_invalid(session, __FUNCTION__);
return -1;
} else {
if (ssh_options_set_algo(session, SSH_COMP_C_S, value) < 0)
return -1;
}
break;
case SSH_OPTIONS_COMPRESSION_S_C:
if (value == NULL) {
ssh_set_error_invalid(session, __FUNCTION__);
return -1;
} else {
if (ssh_options_set_algo(session, SSH_COMP_S_C, value) < 0)
return -1;
}
break;
default:
ssh_set_error(session, SSH_REQUEST_DENIED, "Unkown ssh option %d", ty
pe);
return -1;
break;
} }
return 0; return 0;
} }
int ssh_options_default_known_hosts_file(SSH_OPTIONS *opt) { #ifdef WITH_SERVER
char buffer[1024] = {0}; static int ssh_bind_options_set_algo(ssh_bind sshbind, int algo,
const char *list) {
if (opt->known_hosts_file) { if (!verify_existing_algo(algo, list)) {
return 0; ssh_set_error(sshbind, SSH_REQUEST_DENIED,
} "Setting method: no algorithm for method \"%s\" (%s)\n",
ssh_kex_nums[algo], list);
if (ssh_options_default_ssh_dir(opt) < 0) {
return -1; return -1;
} }
snprintf(buffer, 1024, "%s/known_hosts", opt->ssh_dir); SAFE_FREE(sshbind->wanted_methods[algo]);
opt->known_hosts_file = strdup(buffer); sshbind->wanted_methods[algo] = strdup(list);
if (opt->known_hosts_file == NULL) { if (sshbind->wanted_methods[algo] == NULL) {
ssh_set_error_oom(sshbind);
return -1; return -1;
} }
return 0; return 0;
} }
/** /**
* @brief Set a callback to show connection status in realtime. * @brief This function can set all possible ssh bind options.
* *
* During ssh_connect(), libssh will call the callback with status from * @param session An allocated ssh option structure.
* 0.0 to 1.0
* *
* @param opt The options structure to use. * @param type The option type to set. This could be one of the
* following:
* *
* @param callback A function pointer to a callback in form * SSH_BIND_OPTIONS_LOG_VERBOSITY:
* f(void *userarg, float status). * Set the session logging verbosity (integer).
* *
* @param arg The value to be given as argument to the callback * The verbosity of the messages. Every log smaller
* function when it is called. or
* equal to verbosity will be shown.
* SSH_LOG_NOLOG: No logging
* SSH_LOG_RARE: Rare conditions or warnings
* SSH_LOG_ENTRY: API-accessible entrypoints
* SSH_LOG_PACKET: Packet id and size
* SSH_LOG_FUNCTIONS: Function entering and leavin
g
* *
* @return 0 on success, < 0 on error. * SSH_BIND_OPTIONS_LOG_VERBOSITY_STR:
* Set the session logging verbosity (integer).
* *
* @see ssh_connect() * The verbosity of the messages. Every log smaller
*/ or
int ssh_options_set_status_callback(SSH_OPTIONS *opt, * equal to verbosity will be shown.
void (*callback)(void *arg, float status), void *arg) { * SSH_LOG_NOLOG: No logging
if (opt == NULL || callback == NULL) { * SSH_LOG_RARE: Rare conditions or warnings
return -1; * SSH_LOG_ENTRY: API-accessible entrypoints
} * SSH_LOG_PACKET: Packet id and size
* SSH_LOG_FUNCTIONS: Function entering and leavin
opt->connect_status_function = callback; g
opt->connect_status_arg = arg;
return 0;
}
/**
* @brief Set a timeout for the connection.
* *
* @param opt The options structure to use. * SSH_BIND_OPTIONS_BINDADDR:
* Set the bind address.
* *
* @param seconds Number of seconds. * SSH_BIND_OPTIONS_BINDPORT:
* Set the bind port, default is 22.
* *
* @param usec Number of micro seconds. * SSH_BIND_OPTIONS_HOSTKEY:
* Set the server public key type: ssh-rsa or ssh-ds
s
* (string).
* *
* @return 0 on success, < 0 on error. * SSH_BIND_OPTIONS_DSAKEY:
* * Set the path to the dsa ssh host key (string).
* @bug Currently it only timeouts the socket connection, not the
* complete exchange.
*/
int ssh_options_set_timeout(SSH_OPTIONS *opt, long seconds, long usec) {
if (opt == NULL) {
return -1;
}
opt->timeout=seconds;
opt->timeout_usec=usec;
return 0;
}
/**
* @brief Allow or deny the connection to SSH1 servers.
* *
* Default value is 0 (no connection to SSH1 servers). * SSH_BIND_OPTIONS_RSAKEY:
* Set the path to the ssh host rsa key (string).
* *
* @param opt The options structure to use. * SSH_BIND_OPTIONS_BANNER:
* Set the server banner sent to clients (string).
* *
* @param allow Non zero value allow ssh1. * @param value The value to set. This is a generic pointer and the
* datatype which is used should be set according to t
he
* type set.
* *
* @return 0 on success, < 0 on error. * @return 0 on success, < 0 on error.
*/ */
int ssh_options_allow_ssh1(SSH_OPTIONS *opt, int allow) { int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
if (opt == NULL) { const void *value) {
return -1; char *p, *q;
} int i;
if (allow) {
opt->ssh1allowed = 1;
} else {
opt->ssh1allowed = 0;
}
return 0;
}
/** if (sshbind == NULL) {
* @brief Allow or deny the connection to SSH2 servers.
*
* Default value is 1 (allow connection to SSH2 servers).
*
* @param opt The options structure to use.
*
* @param allow Non zero values allow ssh2.
*
* @return 0 on success, < 0 on error.
*/
int ssh_options_allow_ssh2(SSH_OPTIONS *opt, int allow) {
if (opt == NULL) {
return -1; return -1;
} }
if (allow) { switch (type) {
opt->ssh2allowed = 1; case SSH_BIND_OPTIONS_HOSTKEY:
} else { if (value == NULL) {
opt->ssh2allowed = 0; ssh_set_error_invalid(sshbind, __FUNCTION__);
} return -1;
} else {
if (ssh_bind_options_set_algo(sshbind, SSH_HOSTKEYS, value) < 0)
return -1;
}
break;
case SSH_BIND_OPTIONS_BINDADDR:
if (value == NULL) {
ssh_set_error_invalid(sshbind, __FUNCTION__);
return -1;
} else {
SAFE_FREE(sshbind->bindaddr);
sshbind->bindaddr = strdup(value);
if (sshbind->bindaddr == NULL) {
ssh_set_error_oom(sshbind);
return -1;
}
}
break;
case SSH_BIND_OPTIONS_BINDPORT:
if (value == NULL) {
ssh_set_error_invalid(sshbind, __FUNCTION__);
return -1;
} else {
int *x = (int *) value;
sshbind->bindport = *x & 0xffff;
}
break;
case SSH_BIND_OPTIONS_BINDPORT_STR:
if (value == NULL) {
sshbind->bindport = 22 & 0xffff;
} else {
q = strdup(value);
if (q == NULL) {
ssh_set_error_oom(sshbind);
return -1;
}
i = strtol(q, &p, 10);
if (q == p) {
SAFE_FREE(q);
}
SAFE_FREE(q);
return 0; sshbind->bindport = i & 0xffff;
} }
break;
case SSH_BIND_OPTIONS_LOG_VERBOSITY:
if (value == NULL) {
ssh_set_error_invalid(sshbind, __FUNCTION__);
return -1;
} else {
int *x = (int *) value;
sshbind->log_verbosity = *x & 0xffff;
}
break;
case SSH_BIND_OPTIONS_LOG_VERBOSITY_STR:
if (value == NULL) {
sshbind->log_verbosity = 0;
} else {
q = strdup(value);
if (q == NULL) {
ssh_set_error_oom(sshbind);
return -1;
}
i = strtol(q, &p, 10);
if (q == p) {
SAFE_FREE(q);
}
SAFE_FREE(q);
/** sshbind->log_verbosity = i & 0xffff;
* @brief Change the writer callback for logging. }
* break;
* Default is a write on stderr. case SSH_BIND_OPTIONS_DSAKEY:
* if (value == NULL) {
* @param opt The options structure to use. ssh_set_error_invalid(sshbind, __FUNCTION__);
* return -1;
* @param callback A callback function for the printing. } else {
* SAFE_FREE(sshbind->dsakey);
* @return 0 on success, < 0 on error. sshbind->dsakey = strdup(value);
* if (sshbind->dsakey == NULL) {
* @warning The message string may contain format string characters. ssh_set_error_oom(sshbind);
*/ return -1;
int ssh_options_set_log_function(SSH_OPTIONS *opt, }
void (*callback)(const char *message, SSH_SESSION *session, int priorit }
y)) { break;
if (opt == NULL || callback == NULL) { case SSH_BIND_OPTIONS_RSAKEY:
return -1; if (value == NULL) {
ssh_set_error_invalid(sshbind, __FUNCTION__);
return -1;
} else {
SAFE_FREE(sshbind->rsakey);
sshbind->rsakey = strdup(value);
if (sshbind->rsakey == NULL) {
ssh_set_error_oom(sshbind);
return -1;
}
}
break;
case SSH_BIND_OPTIONS_BANNER:
if (value == NULL) {
ssh_set_error_invalid(sshbind, __FUNCTION__);
return -1;
} else {
SAFE_FREE(sshbind->banner);
sshbind->banner = strdup(value);
if (sshbind->banner == NULL) {
ssh_set_error_oom(sshbind);
return -1;
}
}
break;
default:
ssh_set_error(sshbind, SSH_REQUEST_DENIED, "Unkown ssh option %d", ty
pe);
return -1;
break;
} }
opt->log_function = callback;
return 0; return 0;
} }
#endif
/** /**
* @brief Set the session logging priority.
*
* @param opt The options structure to use.
*
* @param verbosity The verbosity of the messages. Every log smaller or
* equal to verbosity will be shown\n
* SSH_LOG_NOLOG No logging \n
* SSH_LOG_RARE Rare conditions or warnings\n
* SSH_LOG_ENTRY Api-accessible entrypoints\n
* SSH_LOG_PACKET Packet id and size\n
* SSH_LOG_FUNCTIONS function entering and leaving\n
*
* @return 0 on success, < 0 on error.
*/
int ssh_options_set_log_verbosity(SSH_OPTIONS *opt, int verbosity) {
if (opt == NULL) {
return -1;
}
opt->log_verbosity = verbosity;
return 0;
}
/**
* @brief Parse command line arguments. * @brief Parse command line arguments.
* *
* This is a helper for your application to generate the appropriate * This is a helper for your application to generate the appropriate
* options from the command line arguments.\n * options from the command line arguments.\n
* The argv array and argc value are changed so that the parsed * The argv array and argc value are changed so that the parsed
* arguments wont appear anymore in them.\n * arguments wont appear anymore in them.\n
* The single arguments (without switches) are not parsed. thus, * The single arguments (without switches) are not parsed. thus,
* myssh -l user localhost\n * myssh -l user localhost\n
* The command wont set the hostname value of options to localhost. * The command wont set the hostname value of options to localhost.
* *
* @param options An empty option structure pointer. * @param session The session to configure.
* *
* @param argcptr The pointer to the argument count. * @param argcptr The pointer to the argument count.
* *
* @param argv The arguments list pointer. * @param argv The arguments list pointer.
* *
* @returns 0 on success, < 0 on error. * @returns 0 on success, < 0 on error.
* *
* @see ssh_options_new() * @see ssh_session_new()
*/ */
int ssh_options_getopt(SSH_OPTIONS *options, int *argcptr, char **argv) { int ssh_options_getopt(ssh_session session, int *argcptr, char **argv) {
char *user = NULL; char *user = NULL;
char *cipher = NULL; char *cipher = NULL;
char *localaddr = NULL; char *localaddr = NULL;
char *identity = NULL; char *identity = NULL;
char *port = NULL;
char *bindport = NULL;
char **save = NULL; char **save = NULL;
int i = 0; int i = 0;
int argc = *argcptr; int argc = *argcptr;
int port = 22;
int debuglevel = 0; int debuglevel = 0;
int usersa = 0; int usersa = 0;
int usedss = 0; int usedss = 0;
int compress = 0; int compress = 0;
int cont = 1; int cont = 1;
int current = 0; int current = 0;
#ifdef WITH_SSH1 #ifdef WITH_SSH1
int ssh1 = 1; int ssh1 = 1;
#else #else
int ssh1 = 0; int ssh1 = 0;
#endif #endif
int ssh2 = 1; int ssh2 = 1;
#ifdef _MSC_VER
/* Not supported with a Microsoft compiler */
return -1;
#else
int saveoptind = optind; /* need to save 'em */ int saveoptind = optind; /* need to save 'em */
int saveopterr = opterr; int saveopterr = opterr;
save = malloc(argc * sizeof(char *)); save = malloc(argc * sizeof(char *));
if (save == NULL) { if (save == NULL) {
ssh_set_error_oom(session);
return -1; return -1;
} }
opterr = 0; /* shut up getopt */ opterr = 0; /* shut up getopt */
while(cont && ((i = getopt(argc, argv, "c:i:Cl:p:vb:rd12")) != -1)) { while(cont && ((i = getopt(argc, argv, "c:i:Cl:p:vb:t:rd12")) != -1)) {
switch(i) { switch(i) {
case 'l': case 'l':
user = optarg; user = optarg;
break; break;
case 'p': case 'p':
port = atoi(optarg) & 0xffff; port = optarg;
break;
case 't':
bindport = optarg;
break; break;
case 'v': case 'v':
debuglevel++; debuglevel++;
break; break;
case 'r': case 'r':
usersa++; usersa++;
break; break;
case 'd': case 'd':
usedss++; usedss++;
break; break;
skipping to change at line 893 skipping to change at line 934
ssh2 = 0; ssh2 = 0;
ssh1 = 1; ssh1 = 1;
break; break;
default: default:
{ {
char opt[3]="- "; char opt[3]="- ";
opt[1] = optopt; opt[1] = optopt;
save[current] = strdup(opt); save[current] = strdup(opt);
if (save[current] == NULL) { if (save[current] == NULL) {
SAFE_FREE(save); SAFE_FREE(save);
ssh_set_error_oom(session);
return -1; return -1;
} }
current++; current++;
if (optarg) { if (optarg) {
save[current++] = argv[optind + 1]; save[current++] = argv[optind + 1];
} }
} }
} /* switch */ } /* switch */
} /* while */ } /* while */
opterr = saveopterr; opterr = saveopterr;
while (optind < argc) { while (optind < argc) {
save[current++] = argv[optind++]; save[current++] = argv[optind++];
} }
if (usersa && usedss) { if (usersa && usedss) {
ssh_set_error(options, SSH_FATAL, "Either RSA or DSS must be chosen"); ssh_set_error(session, SSH_FATAL, "Either RSA or DSS must be chosen");
cont = 0; cont = 0;
} }
ssh_options_set_log_verbosity(options, debuglevel); ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &debuglevel);
optind = saveoptind; optind = saveoptind;
if(!cont) { if(!cont) {
SAFE_FREE(save); SAFE_FREE(save);
return -1; return -1;
} }
/* first recopy the save vector into the original's */ /* first recopy the save vector into the original's */
for (i = 0; i < current; i++) { for (i = 0; i < current; i++) {
/* don't erase argv[0] */ /* don't erase argv[0] */
argv[ i + 1] = save[i]; argv[ i + 1] = save[i];
} }
argv[current + 1] = NULL; argv[current + 1] = NULL;
*argcptr = current + 1; *argcptr = current + 1;
SAFE_FREE(save); SAFE_FREE(save);
/* set a new option struct */ /* set a new option struct */
if (compress) { if (compress) {
if (ssh_options_set_wanted_algos(options, SSH_COMP_C_S, "zlib") < 0) { if (ssh_options_set(session, SSH_OPTIONS_COMPRESSION_C_S, "zlib") < 0) {
cont = 0; cont = 0;
} }
if (ssh_options_set_wanted_algos(options, SSH_COMP_S_C, "zlib") < 0) { if (ssh_options_set(session, SSH_OPTIONS_COMPRESSION_S_C, "zlib") < 0) {
cont = 0; cont = 0;
} }
} }
if (cont && cipher) { if (cont && cipher) {
if (ssh_options_set_wanted_algos(options, SSH_CRYPT_C_S, cipher) < 0) { if (ssh_options_set(session, SSH_OPTIONS_CIPHERS_C_S, cipher) < 0) {
cont = 0;
}
if (cont && ssh_options_set_wanted_algos(options, SSH_CRYPT_S_C, cipher
) < 0) {
cont = 0;
}
}
if (cont && usersa) {
if (ssh_options_set_wanted_algos(options, SSH_HOSTKEYS, "ssh-rsa") < 0)
{
cont = 0; cont = 0;
} }
} if (cont && ssh_options_set(session, SSH_OPTIONS_CIPHERS_S_C, cipher) <
0) {
if (cont && usedss) {
if (ssh_options_set_wanted_algos(options, SSH_HOSTKEYS, "ssh-dss") < 0)
{
cont = 0; cont = 0;
} }
} }
if (cont && user) { if (cont && user) {
if (ssh_options_set_username(options, user) < 0) { if (ssh_options_set(session, SSH_OPTIONS_USER, user) < 0) {
cont = 0; cont = 0;
} }
} }
if (cont && identity) { if (cont && identity) {
if (ssh_options_set_identity(options, identity) < 0) { if (ssh_options_set(session, SSH_OPTIONS_IDENTITY, identity) < 0) {
cont = 0; cont = 0;
} }
} }
if (cont && localaddr) { ssh_options_set(session, SSH_OPTIONS_PORT_STR, port);
if (ssh_options_set_bind(options, localaddr, 0) < 0) {
cont = 0;
}
}
ssh_options_set_port(options, port); ssh_options_set(session, SSH_OPTIONS_SSH1, &ssh1);
ssh_options_allow_ssh1(options, ssh1); ssh_options_set(session, SSH_OPTIONS_SSH2, &ssh2);
ssh_options_allow_ssh2(options, ssh2);
if (!cont) { if (!cont) {
return -1; return SSH_ERROR;
} }
return 0; return SSH_OK;
#endif
} }
/** /**
* @brief Set the authentication callback. * @brief Parse the ssh config file.
* *
* @param opt The options structure to use. * This should be the last call of all options, it may overwrite options wh
ich
* are already set. It requires that the host name is already set with
* ssh_options_set_host().
* *
* @param cb The callback function to use. * @param session SSH session handle
* *
* @param userdata A pointer to some user data you can pass to the * @param filename The options file to use, if NULL the default
* callback. * ~/.ssh/config will be used.
* *
* @return 0 on success, < 0 on error. * @return 0 on success, < 0 on error.
*
* @see ssh_options_set_host()
*/ */
int ssh_options_set_auth_callback(SSH_OPTIONS *opt, ssh_auth_callback cb, int ssh_options_parse_config(ssh_session session, const char *filename) {
void *userdata) { char *expanded_filename;
if (opt == NULL || cb == NULL) { int r;
if (session == NULL) {
return -1;
}
if (session->host == NULL) {
ssh_set_error_invalid(session, __FUNCTION__);
return -1; return -1;
} }
opt->auth_function = cb; /* set default filename */
opt->auth_userdata = userdata; if (filename == NULL) {
expanded_filename = dir_expand_dup(session, "SSH_DIR/config", 1);
} else {
expanded_filename = dir_expand_dup(session, filename, 1);
}
if (expanded_filename == NULL)
return -1;
return 0; r = ssh_config_parse_file(session, expanded_filename);
free(expanded_filename);
return r;
} }
/** @} */ /** @} */
/* vim: set ts=2 sw=2 et cindent: */ /* vim: set ts=2 sw=2 et cindent: */
 End of changes. 145 change blocks. 
670 lines changed or deleted 736 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/