diff options
author | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2013-07-24 15:21:35 -0500 |
---|---|---|
committer | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2013-07-24 15:21:35 -0500 |
commit | 093ed975800ab1e5c0d73759f07fedf8d5aa2ca6 (patch) | |
tree | d625ba687b185a3984a410f56d9c2e0dade7b114 /kftpgrabber/src/misc/libs/ssh/options.c | |
download | kftpgrabber-093ed975800ab1e5c0d73759f07fedf8d5aa2ca6.tar.gz kftpgrabber-093ed975800ab1e5c0d73759f07fedf8d5aa2ca6.zip |
Initial import of kftpgrabber 0.8.1 from sources
Diffstat (limited to 'kftpgrabber/src/misc/libs/ssh/options.c')
-rw-r--r-- | kftpgrabber/src/misc/libs/ssh/options.c | 341 |
1 files changed, 341 insertions, 0 deletions
diff --git a/kftpgrabber/src/misc/libs/ssh/options.c b/kftpgrabber/src/misc/libs/ssh/options.c new file mode 100644 index 0000000..74ab189 --- /dev/null +++ b/kftpgrabber/src/misc/libs/ssh/options.c @@ -0,0 +1,341 @@ +/* options.c */ +/* handle pre-connection options */ +/* +Copyright 2003 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +License for more details. + +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 +the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, +MA 02110-1301, USA. */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <pwd.h> +#include <sys/types.h> +#include "priv.h" + +SSH_OPTIONS *options_new(){ + SSH_OPTIONS *option=malloc(sizeof(SSH_OPTIONS)); + memset(option,0,sizeof(SSH_OPTIONS)); + option->port=22; /* set the default port */ + option->fd=-1; + return option; +} + +void options_set_port(SSH_OPTIONS *opt, unsigned int port){ + opt->port=port&0xffff; +} +SSH_OPTIONS *options_copy(SSH_OPTIONS *opt){ + SSH_OPTIONS *ret=options_new(); + int i; + ret->fd=opt->fd; + ret->port=opt->port; + if(opt->username) + ret->username=strdup(opt->username); + if(opt->host) + ret->host=strdup(opt->host); + if(opt->bindaddr) + ret->host=strdup(opt->bindaddr); + if(opt->identity) + ret->identity=strdup(opt->identity); + if(opt->ssh_dir) + ret->ssh_dir=strdup(opt->ssh_dir); + if(opt->known_hosts_file) + ret->known_hosts_file=strdup(opt->known_hosts_file); + for(i=0;i<10;++i) + if(opt->wanted_methods[i]) + ret->wanted_methods[i]=strdup(opt->wanted_methods[i]); + ret->passphrase_function=opt->passphrase_function; + ret->connect_status_function=opt->connect_status_function; + ret->connect_status_arg=opt->connect_status_arg; + ret->timeout=opt->timeout; + ret->timeout_usec=opt->timeout_usec; + return ret; +} + +void options_free(SSH_OPTIONS *opt){ + int i; + if(opt->username) + free(opt->username); + if(opt->identity) + free(opt->identity); + /* we don't touch the banner. if the implementation did use it, they have to free it */ + if(opt->host) + free(opt->host); + if(opt->bindaddr) + free(opt->bindaddr); + if(opt->ssh_dir) + free(opt->ssh_dir); + for(i=0;i<10;i++) + if(opt->wanted_methods[i]) + free(opt->wanted_methods[i]); + memset(opt,0,sizeof(SSH_OPTIONS)); + free(opt); +} + + +void options_set_host(SSH_OPTIONS *opt, const char *hostname){ + char *ptr=strdup(hostname); + char *ptr2=strchr(ptr,'@'); + if(opt->host) /* don't leak memory */ + free(opt->host); + if(ptr2){ + *ptr2=0; + opt->host=strdup(ptr2+1); + if(opt->username) + free(opt->username); + opt->username=strdup(ptr); + free(ptr); + } else + opt->host=ptr; +} + +void options_set_fd(SSH_OPTIONS *opt, int fd){ + opt->fd=fd; +} + +void options_set_bindaddr(SSH_OPTIONS *opt, char *bindaddr){ + opt->bindaddr=strdup(bindaddr); +} + +void options_set_username(SSH_OPTIONS *opt,char *username){ + opt->username=strdup(username); +} + +void options_set_ssh_dir(SSH_OPTIONS *opt, char *dir){ + char buffer[1024]; + snprintf(buffer,1024,dir,ssh_get_user_home_dir()); + opt->ssh_dir=strdup(buffer); +} +void options_set_known_hosts_file(SSH_OPTIONS *opt, char *dir){ + char buffer[1024]; + snprintf(buffer,1024,dir,ssh_get_user_home_dir()); + opt->known_hosts_file=strdup(buffer); +} + +void options_set_identity(SSH_OPTIONS *opt, char *identity){ + char buffer[1024]; + snprintf(buffer,1024,identity,ssh_get_user_home_dir()); + opt->identity=strdup(buffer); +} + +/* what's the deal here ? some options MUST be set before authentication or key exchange, + * otherwise default values are going to be used. what must be configurable : + * Public key certification method * + * key exchange method (dh-sha1 for instance)* + * c->s, s->c ciphers * + * c->s s->c macs * + * c->s s->c compression */ + +/* they all return 0 if all went well, 1 or !=0 if not. the most common error is unmatched algo (unimplemented) */ +/* don't forget other errors can happen if no matching algo is found in sshd answer */ + +int options_set_wanted_method(SSH_OPTIONS *opt,int method, char *list){ + if(method > 9 || method < 0){ + ssh_set_error(NULL,SSH_FATAL,"method %d out of range",method); + return -1; + } + if( (!opt->use_nonexisting_algo) && !verify_existing_algo(method,list)){ + ssh_set_error(NULL,SSH_FATAL,"Setting method : no algorithm for method \"%s\" (%s)\n",ssh_kex_nums[method],list); + return -1; + } + if(opt->wanted_methods[method]) + free(opt->wanted_methods[method]); + opt->wanted_methods[method]=strdup(list); + return 0; +} + +static char *get_username_from_uid(int uid){ + struct passwd *pwd; + char *user; + while((pwd=getpwent())){ + if(pwd->pw_uid == uid){ + user=strdup(pwd->pw_name); + endpwent(); + return user; + } + } + endpwent(); + ssh_set_error(NULL,SSH_FATAL,"uid %d doesn't exist !",uid); + return NULL; +} + +/* this function must be called when no specific username has been asked. it has to guess it */ +int options_default_username(SSH_OPTIONS *opt){ + char *user; + if(opt->username) + return 0; + user=getenv("USER"); + if(user){ + opt->username=strdup(user); + return 0; + } + user=get_username_from_uid(getuid()); + if(user){ + opt->username=user; + return 0; + } + return -1; +} + +int options_default_ssh_dir(SSH_OPTIONS *opt){ + char buffer[256]; + if(opt->ssh_dir) + return 0; + snprintf(buffer,256,"%s/.ssh/",ssh_get_user_home_dir()); + opt->ssh_dir=strdup(buffer); + return 0; +} + +int options_default_known_hosts_file(SSH_OPTIONS *opt){ + char buffer[1024]; + if(opt->known_hosts_file) + return 0; + options_default_ssh_dir(opt); + snprintf(buffer,1024,"%s/known_hosts",opt->ssh_dir); + opt->known_hosts_file=strdup(buffer); + return 0; +} + +void options_set_status_callback(SSH_OPTIONS *opt, void (*callback)(void *arg, float status), void *arg ){ + opt->connect_status_function=callback; + opt->connect_status_arg=arg; +} + +void options_set_timeout(SSH_OPTIONS *opt, long seconds,long usec){ + opt->timeout=seconds; + opt->timeout_usec=usec; +} + +SSH_OPTIONS *ssh_getopt(int *argcptr, char **argv){ + int i; + int argc=*argcptr; + char *user=NULL; + int port=22; + int debuglevel=0; + int usersa=0; + int usedss=0; + int compress=0; + int cont=1; + char *cipher=NULL; + char *localaddr=NULL; + char *identity=NULL; + char **save=malloc(argc * sizeof(char *)); + int current=0; + + int saveoptind=optind; /* need to save 'em */ + int saveopterr=opterr; + SSH_OPTIONS *options; + opterr=0; /* shut up getopt */ + while(cont && ((i=getopt(argc,argv,"c:i:Cl:p:vb:rd12"))!=-1)){ + + switch(i){ + case 'l': + user=optarg; + break; + case 'p': + port=atoi(optarg)&0xffff; + break; + case 'v': + debuglevel++; + break; + case 'r': + usersa++; + break; + case 'd': + usedss++; + break; + case 'c': + cipher=optarg; + break; + case 'i': + identity=optarg; + break; + case 'b': + localaddr=optarg; + break; + case 'C': + compress++; + break; + case '2': + break; /* only ssh2 support till now */ + case '1': + ssh_set_error(NULL,SSH_FATAL,"libssh does not support SSH1 protocol"); + cont =0; + break; + default: + { + char opt[3]="- "; + opt[1]=optopt; + save[current++]=strdup(opt); + if(optarg) + save[current++]=argv[optind+1]; + } + } + } + opterr=saveopterr; + while(optind < argc) + save[current++]=argv[optind++]; + + if(usersa && usedss){ + ssh_set_error(NULL,SSH_FATAL,"either RSA or DSS must be chosen"); + cont=0; + } + ssh_set_verbosity(debuglevel); + optind=saveoptind; + if(!cont){ + free(save); + return NULL; + } + /* first recopy the save vector into original's */ + for(i=0;i<current;i++) + argv[i+1]=save[i]; /* don't erase argv[0] */ + argv[current+1]=NULL; + *argcptr=current+1; + free(save); + /* set a new option struct */ + options=options_new(); + if(compress){ + if(options_set_wanted_method(options,KEX_COMP_C_S,"zlib")) + cont=0; + if(options_set_wanted_method(options,KEX_COMP_S_C,"zlib")) + cont=0; + } + if(cont &&cipher){ + if(options_set_wanted_method(options,KEX_CRYPT_C_S,cipher)) + cont=0; + if(cont && options_set_wanted_method(options,KEX_CRYPT_S_C,cipher)) + cont=0; + } + if(cont && usersa) + if(options_set_wanted_method(options,KEX_HOSTKEY,"ssh-rsa")) + cont=0; + if(cont && usedss) + if(options_set_wanted_method(options,KEX_HOSTKEY,"ssh-dss")) + cont=0; + if(cont && user) + options_set_username(options,user); + if(cont && identity) + options_set_identity(options,identity); + if(cont && localaddr) + options_set_bindaddr(options,localaddr); + options_set_port(options,port); + if(!cont){ + options_free(options); + return NULL; + } else + return options; +} |