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/ |