static void client_alive_check(void) { static int had_channel = 0; int id; id = channel_find_open(); if (id == -1) { if (!had_channel) return; packet_disconnect("No open channels after timeout!"); } had_channel = 1; /* timeout, check to see how many we have had */ if (++client_alive_timeouts > options.client_alive_count_max) packet_disconnect("Timeout, your session not responding."); /* * send a bogus channel request with "wantreply", * we should get back a failure */ channel_request_start(id, "*****@*****.**", 1); packet_send(); }
static void server_input_channel_req(int type, u_int32_t seq, void *ctxt) { Channel *c; int id, reply, success = 0; char *rtype; id = packet_get_int(); rtype = packet_get_string(NULL); reply = packet_get_char(); debug("server_input_channel_req: channel %d request %s reply %d", id, rtype, reply); if ((c = channel_lookup(id)) == NULL) packet_disconnect("server_input_channel_req: " "unknown channel %d", id); if (!strcmp(rtype, "*****@*****.**")) { packet_check_eom(); chan_rcvd_eow(c); } else if ((c->type == SSH_CHANNEL_LARVAL || c->type == SSH_CHANNEL_OPEN) && strcmp(c->ctype, "session") == 0) success = session_input_channel_req(c, rtype); if (reply) { packet_start(success ? SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE); packet_put_int(c->remote_id); packet_send(); } free(rtype); }
/*ARGSUSED*/ static void input_service_request(int type, u_int32_t seq, void *ctxt) { Authctxt *authctxt = ctxt; u_int len; int acceptit = 0; char *service = packet_get_cstring(&len); packet_check_eom(); if (authctxt == NULL) fatal("input_service_request: no authctxt"); if (strcmp(service, "ssh-userauth") == 0) { if (!authctxt->success) { acceptit = 1; /* now we can handle user-auth requests */ dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request); } } /* XXX all other service requests are denied */ if (acceptit) { packet_start(SSH2_MSG_SERVICE_ACCEPT); packet_put_cstring(service); packet_send(); packet_write_wait(); } else { debug("bad service request %s", service); packet_disconnect("bad service request %s", service); } free(service); }
static Channel * server_request_session(void) { Channel *c; debug("input_session_request"); packet_check_eom(); if (no_more_sessions) { packet_disconnect("Possible attack: attempt to open a session " "after additional sessions disabled"); } /* * A server session has no fd to read or write until a * CHANNEL_REQUEST for a shell is made, so we set the type to * SSH_CHANNEL_LARVAL. Additionally, a callback for handling all * CHANNEL_REQUEST messages is registered. */ c = channel_new("session", SSH_CHANNEL_LARVAL, -1, -1, -1, /*window size*/0, CHAN_SES_PACKET_DEFAULT, 0, "server-session", 1); if (session_open(the_authctxt, c->self) != 1) { debug("session open failed, free channel %d", c->self); channel_free(c); return NULL; } channel_register_cleanup(c->self, session_close_by_channel, 0); return c; }
/* IPv4 only */ static void check_ip_options(int socket, char *ipaddr) { #ifdef IP_OPTIONS u_char options[200]; char text[sizeof(options) * 3 + 1]; socklen_t option_size; int i, ipproto; struct protoent *ip; if ((ip = getprotobyname("ip")) != NULL) ipproto = ip->p_proto; else ipproto = IPPROTO_IP; option_size = sizeof(options); if (getsockopt(socket, ipproto, IP_OPTIONS, options, &option_size) >= 0 && option_size != 0) { text[0] = '\0'; for (i = 0; i < option_size; i++) snprintf(text + i*3, sizeof(text) - i*3, " %2.2x", options[i]); logit("Connection from %.100s with IP options:%.800s", ipaddr, text); packet_disconnect("Connection from %.100s with IP options:%.800s", ipaddr, text); } #endif /* IP_OPTIONS */ }
/* * Performs authentication of an incoming connection. Session key has already * been exchanged and encryption is enabled. */ Authctxt * do_authentication(void) { Authctxt *authctxt; u_int ulen; char *user, *style = NULL; /* Get the name of the user that we wish to log in as. */ packet_read_expect(SSH_CMSG_USER); /* Get the user name. */ user = packet_get_string(&ulen); packet_check_eom(); if ((style = strchr(user, ':')) != NULL) *style++ = '\0'; authctxt = authctxt_new(); authctxt->user = user; authctxt->style = style; /* Verify that the user is a valid user. */ if ((authctxt->pw = PRIVSEP(getpwnamallow(user))) != NULL) authctxt->valid = 1; else { debug("do_authentication: illegal user %s", user); authctxt->pw = fakepw(); } setproctitle("%s%s", authctxt->pw ? user : "******", use_privsep ? " [net]" : ""); #ifdef USE_PAM if (options.use_pam) PRIVSEP(start_pam(user)); #endif /* * If we are not running as root, the user must have the same uid as * the server. (Unless you are running Windows) */ #ifndef HAVE_CYGWIN if (!use_privsep && getuid() != 0 && authctxt->pw && authctxt->pw->pw_uid != getuid()) packet_disconnect("Cannot change user when server not running as root."); #endif /* * Loop until the user has been authenticated or the connection is * closed, do_authloop() returns only if authentication is successful */ do_authloop(authctxt); /* The user has been authenticated and accepted. */ packet_start(SSH_SMSG_SUCCESS); packet_send(); packet_write_wait(); return (authctxt); }
void userauth_finish(Authctxt *authctxt, int authenticated, char *method) { char *methods; if (!authctxt->valid && authenticated) fatal("INTERNAL ERROR: authenticated invalid user %s", authctxt->user); /* Special handling for root */ if (authenticated && authctxt->pw->pw_uid == 0 && !auth_root_allowed(method)) authenticated = 0; #ifdef USE_PAM if (!use_privsep && authenticated && authctxt->user && !do_pam_account(authctxt->user, NULL)) authenticated = 0; #endif /* USE_PAM */ #ifdef _UNICOS if (authenticated && cray_access_denied(authctxt->user)) { authenticated = 0; fatal("Access denied for user %s.",authctxt->user); } #endif /* _UNICOS */ /* Log before sending the reply */ auth_log(authctxt, authenticated, method, " ssh2"); if (authctxt->postponed) return; /* XXX todo: check if multiple auth methods are needed */ if (authenticated == 1) { /* turn off userauth */ dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore); packet_start(SSH2_MSG_USERAUTH_SUCCESS); packet_send(); packet_write_wait(); /* now we can break out */ authctxt->success = 1; } else { if (authctxt->failures++ > AUTH_FAIL_MAX) { packet_disconnect(AUTH_FAIL_MSG, authctxt->user); } #ifdef _UNICOS if (strcmp(method, "password") == 0) cray_login_failure(authctxt->user, IA_UDBERR); #endif /* _UNICOS */ methods = authmethods_get(); packet_start(SSH2_MSG_USERAUTH_FAILURE); packet_put_cstring(methods); packet_put_char(0); /* XXX partial success, unused */ packet_send(); packet_write_wait(); xfree(methods); } }
/* etnlegend, 2006.04.25, clean up bbsd_single ... */ #include "bbs.h" #include <arpa/telnet.h> #include <sys/resource.h> #ifdef HAVE_REVERSE_DNS #include <netdb.h> #endif /* HAVE_REVERSE_DNS */ #undef LOAD_LIMIT /* Temporarily Disable All Load Limit Detection */ #if defined(LOAD_LIMIT) && defined(AIX) #include <rpcsvc/rstat.h> #endif /* LOAD_LIMIT && AIX */ #define SOCKFD 3 /* listen sock file descriptor, should be set to 3 for consistent ! */ #define MAX_PENDING_CONNECTIONS 50 #define MAXLIST 1000 #define CON_THRESHOLD (5.0/18) /* (1000.0/3600) */ #define CON_THRESHOLD2 1.0 #ifdef HAVE_IPV6_SMTH #define KBS_SIN_MEMBER(_sin,_member) _sin.sin6_##_member #define KBS_SIN_FAMILY AF_INET6 #define KBS_SIN_ADDR_DEFAULT in6addr_any struct ip_struct { /* size on 32-bit / 64-bit machine */ struct in6_addr ip; /* 16 16 */ time_t first; /* 4 8 */ time_t last; /* 4 8 */ int t; /* 4 4 */ }; /* 28 36 bytes */ typedef struct sockaddr_in6 KBS_SOCKADDR_IN; typedef struct in6_addr KBS_IN_ADDR; #ifdef LEGACY_IPV4_DISPLAY #define KBS_SET_FROMHOST(_sin,_from) \ ( \ !ISV4ADDR(KBS_SIN_MEMBER(_sin,addr))? \ inet_ntop(AF_INET6,&KBS_SIN_MEMBER(_sin,addr),_from,IPLEN): \ inet_ntop(AF_INET,&KBS_SIN_MEMBER(_sin,addr).s6_addr[12],_from,IPLEN) \ ) #endif /* LEGACY_IPV4_DISPLAY */ #else /* ! HAVE_IPV6_SMTH */ #define KBS_SIN_MEMBER(_sin,_member) _sin.sin_##_member #define KBS_SIN_FAMILY AF_INET #define KBS_SIN_ADDR_DEFAULT inaddr_any struct ip_struct { /* size on 32-bit / 64-bit machine */ unsigned char ip[4]; /* 4 4 */ int t; /* 4 4 */ time_t first; /* 4 8 */ time_t last; /* 4 8 */ }; /* 16 24 bytes */ typedef struct sockaddr_in KBS_SOCKADDR_IN; typedef struct in_addr KBS_IN_ADDR; #endif /* HAVE_IPV6_SMTH */ #define KBS_SET_SIN_FAMILY(_sin) do{KBS_SIN_MEMBER(_sin,family)=KBS_SIN_FAMILY;}while(0) #define KBS_SET_SIN_PORT(_sin,_port) do{KBS_SIN_MEMBER(_sin,port)=htons(_port);}while(0) #define KBS_SET_SIN_ADDR(_sin,_addr) do{KBS_SIN_MEMBER(_sin,addr)=_addr;}while(0) #ifndef KBS_SET_FROMHOST #define KBS_SET_FROMHOST(_sin,_from) inet_ntop(KBS_SIN_FAMILY,&KBS_SIN_MEMBER(_sin,addr),_from,IPLEN) #endif /* KBS_SET_FROMHOST */ #ifndef SSHBBS #define KBS_WRITE(_fd,_ptr,_len) write(_fd,_ptr,_len) static const unsigned char cmd[]={ IAC,DO,TELOPT_TTYPE, /* cmd 0 size = 3 */ IAC,SB,TELOPT_TTYPE,TELQUAL_SEND,IAC,SE, /* cmd 1 size = 6 */ IAC,WILL,TELOPT_ECHO, /* cmd 2 size = 3 */ IAC,WILL,TELOPT_SGA, /* cmd 3 size = 3 */ IAC,WILL,TELOPT_BINARY, /* cmd 4 size = 3 */ IAC,DO,TELOPT_NAWS, /* cmd 5 size = 3 */ IAC,DO,TELOPT_BINARY /* cmd 6 size = 3 */ }; /* total size = 24 */ #ifndef HAVE_IPV6_SMTH static struct in_addr inaddr_any; #endif /* HAVE_IPV6_SMTH */ static int mport; static int no_fork; static int server_pid; const select_func x_select=select; const read_func x_read=read; #else /* SSHBBS */ #include "ssh_funcs.h" #define KBS_WRITE(_fd,_ptr,_len) ssh_write(_fd,_ptr,_len) extern char **saved_argv; static int ssh_exiting; const select_func x_select=ssh_select; const read_func x_read=ssh_read; #endif /* ! SSHBBS */ static const int max_load = 79; static int heavy_load; static int initIP; static struct ip_struct *ips; static struct ip_struct *bads; static struct ip_struct *proxies; static inline int proxy_getpeername(int sockfd,struct sockaddr *addr,socklen_t *len) { return getpeername(sockfd,addr,len); } static inline int local_Net_Sleep(time_t time) { fd_set fds,efds; struct timeval tv; char buf[256]; FD_ZERO(&fds);FD_ZERO(&efds); FD_SET(0,&fds);FD_SET(0,&efds); for (tv.tv_sec=time,tv.tv_usec=0;select(1,&fds,NULL,&efds,&tv)>0;tv.tv_sec=time,tv.tv_usec=0) { if (FD_ISSET(0,&efds)||!(recv(0,buf,256,0)>0)) break; FD_SET(0,&fds);FD_SET(0,&efds); } return 0; } static inline int local_prints(const char *fmt,...) { va_list ap; char buf[1024]; va_start(ap,fmt); vsprintf(buf,fmt,ap); va_end(ap); return KBS_WRITE(0,buf,strlen(buf)); } #ifdef LOAD_LIMIT static inline int get_load(double *load) { #if defined(HAVE_GETLOADAVG) return getloadavg(load,3); #elif defined(LINUX) /* ! HAVE_GETLOADAVG && LINUX */ FILE *fp; int ret; double avg[3]; load[0]=0; load[1]=0; load[2]=0; if (!(fp=fopen("/proc/loadavg","r"))) return 0; ret=fscanf(fp,"%g %g %g",&avg[0],&avg[1],&avg[2]); fclose(fp); switch (ret) { case 3: load[2]=avg[2]; case 2: load[1]=avg[1]; case 1: load[0]=avg[0]; break; default: return -1; } return ret; #else /* ! HAVE_GETLOADAVG && ! LINUX */ struct statstime rsts; rstat("localhost",&rsts); load[0]=(rs.avenrun[0]*0.00390625); /* div by 256 */ load[1]=(rs.avenrun[1]*0.00390625); load[2]=(rs.avenrun[2]*0.00390625); #endif /* HAVE_GETLOADAVG */ } #endif /* LOAD_LIMIT */ static void sig_user1(int sig) { heavy_load=1; return; } static void sig_user2(int sig) { heavy_load=0; return; } static void sig_reaper(int sig) { while (waitpid(-1,NULL,(WNOHANG|WUNTRACED))>0) continue; return; } static void sig_mainterm(int sig) { exit(0); } static int main_signals(void) { struct sigaction act; sigemptyset(&act.sa_mask); act.sa_flags=0; act.sa_flags=SA_RESTART; act.sa_handler=sig_mainterm; sigaction(SIGTERM,&act,NULL); act.sa_handler=sig_user1; sigaction(SIGUSR1,&act,NULL); act.sa_handler=sig_user2; sigaction(SIGUSR2,&act,NULL); act.sa_handler=SIG_IGN; sigaction(SIGPIPE,&act,NULL); act.sa_handler=SIG_IGN; sigaction(SIGTTOU,&act,NULL); act.sa_handler=SIG_IGN; sigaction(SIGHUP,&act,NULL); #ifndef AIX act.sa_handler=sig_reaper; act.sa_flags=SA_RESTART; #else /* AIX */ act.sa_handler=NULL; act.sa_flags=(SA_RESTART|SA_NOCLDWAIT); #endif /* ! AIX */ sigaction(SIGCHLD,&act,NULL); return 0; } #ifdef HAVE_REVERSE_DNS static void dns_query_timeout(int sig) { longjmp(byebye,sig); } static void getremotehost(char *host,size_t len) { KBS_SOCKADDR_IN sin; socklen_t sinlen; struct hostent *hp; char buf[128],*p; sinlen=sizeof(KBS_SOCKADDR_IN); proxy_getpeername(0,(struct sockaddr*)&sin,&sinlen); if (!setjmp(byebye)) { signal(SIGALRM,dns_query_timeout); alarm(5); hp=gethostbyaddr(&(KBS_SIN_MEMBER(sin,addr)),sizeof(KBS_SIN_MEMBER(sin,addr)),KBS_SIN_MEMBER(sin,family)); alarm(0); } if (hp #ifdef HAVE_IPV6_SMTH &&!strchr(hp->h_name,':') #endif /* HAVE_IPV6_SMTH */ ) snprintf(buf,128,"%s",hp->h_name); else KBS_SET_FROMHOST(sin,buf); if ((p=strstr(buf,"."NAME_BBS_ENGLISH))) *p=0; snprintf(host,len,"%s",buf); return; } #endif /* HAVE_REVERSE_DNS */ int check_IP_lists( #ifndef HAVE_IPV6_SMTH unsigned int IP2 #else /* HAVE_IPV6_SMTH */ struct in6_addr sip #endif /* ! HAVE_IPV6_SMTH */ ) { FILE *fp; char buf[1024]; int i,found,min,ret; time_t now; #ifndef HAVE_IPV6_SMTH unsigned int ip[4]; #else /* HAVE_IPV6_SMTH */ struct in6_addr rip; #endif /* ! HAVE_IPV6_SMTH */ found=0;min=0;ret=0; if (!initIP) { ips=(struct ip_struct*)malloc(MAXLIST*sizeof(struct ip_struct)); bads=(struct ip_struct*)malloc(MAXLIST*sizeof(struct ip_struct)); proxies=(struct ip_struct*)malloc(MAXLIST*sizeof(struct ip_struct)); memset(ips,0,MAXLIST*sizeof(struct ip_struct)); memset(bads,0,MAXLIST*sizeof(struct ip_struct)); memset(proxies,0,MAXLIST*sizeof(struct ip_struct)); if (!ips||!bads||!proxies) return -1; if ((fp=fopen(".denyIP","r"))) { for (i=0;fgets(buf,1024,fp);i++) { #ifndef HAVE_IPV6_SMTH if (!(sscanf(buf,"%d.%d.%d.%d",&ip[0],&ip[1],&ip[2],&ip[3])>0)) break; bads[i].ip[0]=ip[0]; bads[i].ip[1]=ip[1]; bads[i].ip[2]=ip[2]; bads[i].ip[3]=ip[3]; #else /* HAVE_IPV6_SMTH */ if (!(sscanf(buf,"%02hhX%02hhX:%02hhX%02hhX:%02hhX%02hhX:%02hhX%02hhX:" "%02hhX%02hhX:%02hhX%02hhX:%02hhX%02hhX:%02hhX%02hhX",&rip.s6_addr[0], &rip.s6_addr[1],&rip.s6_addr[2],&rip.s6_addr[3],&rip.s6_addr[4],&rip.s6_addr[5], &rip.s6_addr[6],&rip.s6_addr[7],&rip.s6_addr[8],&rip.s6_addr[9],&rip.s6_addr[10], &rip.s6_addr[11],&rip.s6_addr[12],&rip.s6_addr[13],&rip.s6_addr[14],&rip.s6_addr[15])>0)) break; ip_cpy(bads[i].ip,rip); #endif /* ! HAVE_IPV6_SMTH */ } fclose(fp); } if ((fp=fopen("etc/proxyIP","r"))) { for (i=0;fgets(buf,1024,fp);i++) { #ifndef HAVE_IPV6_SMTH if (!(sscanf(buf,"%d.%d.%d.%d",&ip[0],&ip[1],&ip[2],&ip[3])>0)) break; proxies[i].ip[0]=ip[0]; proxies[i].ip[1]=ip[1]; proxies[i].ip[2]=ip[2]; proxies[i].ip[3]=ip[3]; #else /* HAVE_IPV6_SMTH */ if (!(sscanf(buf,"%02hhX%02hhX:%02hhX%02hhX:%02hhX%02hhX:%02hhX%02hhX:" "%02hhX%02hhX:%02hhX%02hhX:%02hhX%02hhX:%02hhX%02hhX",&rip.s6_addr[0], &rip.s6_addr[1],&rip.s6_addr[2],&rip.s6_addr[3],&rip.s6_addr[4],&rip.s6_addr[5], &rip.s6_addr[6],&rip.s6_addr[7],&rip.s6_addr[8],&rip.s6_addr[9],&rip.s6_addr[10], &rip.s6_addr[11],&rip.s6_addr[12],&rip.s6_addr[13],&rip.s6_addr[14],&rip.s6_addr[15])>0)) break; ip_cpy(proxies[i].ip,rip); #endif /* ! HAVE_IPV6_SMTH */ } fclose(fp); } initIP=1; } now=time(NULL); #ifndef HAVE_IPV6_SMTH if (!(ip[0]=(IP2&0xFF))) return 0; ip[1]=((IP2>>8)&0xFF); ip[2]=((IP2>>16)&0xFF); ip[3]=((IP2>>24)&0xFF); for (i=0;i<MAXLIST;i++) { if (!(bads[i].ip[0])) break; if ((ip[0]==bads[i].ip[0])&&(ip[1]==bads[i].ip[1]) &&(ip[2]==bads[i].ip[2])&&(ip[3]==bads[i].ip[3])) return 1; } for (i=0;i<MAXLIST;i++) { if (!(proxies[i].ip[0])) break; if ((ip[0]==proxies[i].ip[0])&&(ip[1]==proxies[i].ip[1]) &&(ip[2]==proxies[i].ip[2])&&(ip[3]==proxies[i].ip[3])) return 0; } for (i=0;i<MAXLIST;i++) { if ((double)(now-ips[i].last)>3600) ips[i].ip[0]=0; if ((ip[0]==ips[i].ip[0])&&(ip[1]==ips[i].ip[1]) &&(ip[2]==ips[i].ip[2])&&(ip[3]==ips[i].ip[3])) { if (!((double)(now-ips[i].last)>CON_THRESHOLD2)) { if ((fp=fopen(".IPdenys","a"))) { fprintf(fp,"0 %ld %d.%d.%d.%d %d\n",now,ip[0],ip[1],ip[2],ip[3],ips[i].t); fclose(fp); } ret=1; } found=1; ips[i].last=now; ips[i].t++; if (!(ips[i].t<10)&&!((ips[i].t/(double)(ips[i].last-ips[i].first))<CON_THRESHOLD)) { ips[i].t=100000; if ((fp=fopen(".IPdenys","a"))) { fprintf(fp,"1 %ld %d.%d.%d.%d %d\n",now,ip[0],ip[1],ip[2],ip[3],ips[i].t); fclose(fp); } ret=1; } break; } if (ips[i].last<ips[min].last) min=i; } if (!found) { ips[min].ip[0]=ip[0]; ips[min].ip[1]=ip[1]; ips[min].ip[2]=ip[2]; ips[min].ip[3]=ip[3]; ips[min].first=now; ips[min].last=now; ips[min].t=1; } #else /* HAVE_IPV6_SMTH */ memset(&rip,0,sizeof(struct in6_addr)); for (i=0;i<MAXLIST;i++) { if (!ip_cmp(rip,bads[i].ip)) break; if (!ip_cmp(sip,bads[i].ip)) return 1; } for (i=0;i<MAXLIST;i++) { if (!ip_cmp(rip,proxies[i].ip)) break; if (!ip_cmp(sip,proxies[i].ip)) return 0; } for (i=0;i<MAXLIST;i++) { if ((double)(now-ips[i].last)>3600) memset(&ips[i].ip,0,sizeof(struct in6_addr)); if (!ip_cmp(ips[i].ip,sip)) { if (!((double)(now-ips[i].last)>CON_THRESHOLD2)) { if ((fp=fopen(".IPdenys","a"))) { fprintf(fp,"0 %ld %02hhX%02hhX:%02hhX%02hhX:%02hhX%02hhX:%02hhX%02hhX:" "%02hhX%02hhX:%02hhX%02hhX:%02hhX%02hhX:%02hhX%02hhX %d\n",now,rip.s6_addr[0], rip.s6_addr[1],rip.s6_addr[2],rip.s6_addr[3],rip.s6_addr[4],rip.s6_addr[5], rip.s6_addr[6],rip.s6_addr[7],rip.s6_addr[8],rip.s6_addr[9],rip.s6_addr[10], rip.s6_addr[11],rip.s6_addr[12],rip.s6_addr[13],rip.s6_addr[14],rip.s6_addr[15],ips[i].t); fclose(fp); } ret=1; } found=1; ips[i].last=now; ips[i].t++; if (!(ips[i].t<10)&&!((ips[i].t/(double)(ips[i].last-ips[i].first))<CON_THRESHOLD)) { ips[i].t=100000; if ((fp=fopen(".IPdenys","a"))) { fprintf(fp,"1 %ld %02hhX%02hhX:%02hhX%02hhX:%02hhX%02hhX:%02hhX%02hhX:" "%02hhX%02hhX:%02hhX%02hhX:%02hhX%02hhX:%02hhX%02hhX %d\n",now,rip.s6_addr[0], rip.s6_addr[1],rip.s6_addr[2],rip.s6_addr[3],rip.s6_addr[4],rip.s6_addr[5], rip.s6_addr[6],rip.s6_addr[7],rip.s6_addr[8],rip.s6_addr[9],rip.s6_addr[10], rip.s6_addr[11],rip.s6_addr[12],rip.s6_addr[13],rip.s6_addr[14],rip.s6_addr[15],ips[i].t); fclose(fp); } ret=1; } break; } if (ips[i].last<ips[min].last) min=i; } if (!found) { ip_cpy(ips[min].ip,rip); ips[min].first=now; ips[min].last=now; ips[min].t=1; } #endif /* ! HAVE_IPV6_SMTH */ return ret; } #ifdef SECONDSITE int frommain=0; #endif static int bbs_main(char *argv) { #define BBS_MAIN_EXIT(time) do{local_Net_Sleep(time);shutdown(0,2);close(0);return -1;}while(0) FILE *fp; struct stat st; struct rlimit rl; char buf[256]; #ifndef DEBUG if (strcmp(getSession()->fromhost,"0.0.0.0")&&strcmp(getSession()->fromhost,"127.0.0.1") &&((fp=fopen("NOLOGIN","r")))) { while (fgets(buf,256,fp)) local_prints("%s",buf); fclose(fp); BBS_MAIN_EXIT(20); } #endif /* ! DEBUG */ #ifdef LOAD_LIMIT if (!stat("NO_LOAD_LIMIT",&st)&&S_ISREG(st.st_mode)) { double load,cpu_load[3]; get_load(cpu_load); load=cpu_load[0]; local_prints("CPU 最近 (1,10,15) 分钟的平均负荷分别为 %.2f, %.2f, %.2f (目前上限 = %d)\r\n", cpu_load[0],cpu_load[1],cpu_load[2],max_load); if ((load<0)||(load>max_load)) { local_prints("%s\r\n\r\n%s\r\n%s\r\n", "很抱歉, 目前 CPU 负荷过重, 请稍候再来", "因为重复连接对本站冲击太大, 请您配合, 不要重复多次连接", "请您先休息 10 分钟, 然后再连接本站, 非常感谢!"); BBS_MAIN_EXIT(((time_t)load)); } #ifdef AIX { int free=psdanger(-1); int safe=psdanger(SIGDANGER); int danger=125000; local_prints("RAM 当前空闲页数高出警戒阈值 %d (警戒阈值 = %d)\r\n\r\n",safe,(free-safe)); if (safe<danger) { if ((server_pid!=-1)&&(!heavy_load)) kill(server_pid,SIGUSR1); local_prints("%s\r\n\r\n%s\r\n%s\r\n", "很抱歉, 目前 RAM 被过度使用, 请稍候再来", "因为重复连接对本站冲击太大, 请您配合, 不要重复多次连接", "请您先休息 10 分钟, 然后再连接本站, 非常感谢!"); BBS_MAIN_EXIT(60); } if ((server_pid!=-1)&&heavy_load) kill(server_pid,SIGUSR2); } #endif /* AIX */ } #endif /* LOAD_LIMIT */ #ifdef BBSRF_CHROOT if (chroot(BBSHOME)==-1) { local_prints("Error while chroot to %s, exiting ...\r\n",BBSHOME); return -1; } #endif /* BBSRF_CHROOT */ #ifdef SECONDSITE #define deg(x...) if (!strncmp(getSession()->fromhost, "10.", 3)) { char ipbuf[16]; int len=0; while ((ipbuf[len] = igetkey()) != '\n') { deg("%d:%d\n",getpid(), ipbuf[len]); len++; if (len >= 15) break; } ipbuf[len]='\0'; strcpy(getSession()->fromhost, ipbuf); frommain=1; } #endif /* SECONDSITE */ getSession()->fromhost[IPLEN-1]=0; *buf = 0; if (check_ban_IP(getSession()->fromhost,buf)>0) { local_prints("本站目前不欢迎来自 %s 访问!\r\n原因: %s\r\n\r\n",getSession()->fromhost,buf); BBS_MAIN_EXIT(60); } #ifdef HAVE_REVERSE_DNS getremotehost(getSession()->fromhost,IPLEN); #endif /* HAVE_REVERSE_DNS */ if (stat("core",&st)==-1) { rl.rlim_cur=125829120; /* 120M */ rl.rlim_max=209715200; /* 200M */ setrlimit(RLIMIT_CORE,&rl); } main_bbs(0,argv); return -1; #undef BBS_MAIN_EXIT } #ifndef SSHBBS static int telnet_init(void) { send(0,&cmd[0],3*sizeof(unsigned char),0); send(0,&cmd[3],6*sizeof(unsigned char),0); send(0,&cmd[9],3*sizeof(unsigned char),0); send(0,&cmd[12],3*sizeof(unsigned char),0); send(0,&cmd[15],3*sizeof(unsigned char),0); send(0,&cmd[18],3*sizeof(unsigned char),0); send(0,&cmd[21],3*sizeof(unsigned char),0); return 0; } static int start_daemon(int inetd,int port,const char *addr) { static const int optval=1; KBS_SOCKADDR_IN sin; KBS_IN_ADDR inaddr; char pid_file_name[PATHLEN],pid_string[16]; int sockfd,fd,maxfd; if (chdir(BBSHOME)==-1) exit(3); umask(0007); mport=port; if (inetd) { if ((fd=open("/dev/null",O_RDWR,0660))==-1||dup2(fd,1)==-1||dup2(fd,2)==-1) exit(2); if (fd>2) close(fd); } else { if (!no_fork) { switch (fork()) { case -1: exit(2); case 0: break; default: exit(0); } setsid(); switch (fork()) { case -1: exit(2); case 0: break; default: exit(0); } } KBS_SET_SIN_FAMILY(sin); if (!addr||!(inet_pton(KBS_SIN_FAMILY,addr,&inaddr)>0)) { KBS_SET_SIN_ADDR(sin,KBS_SIN_ADDR_DEFAULT); snprintf(pid_file_name,PATHLEN,"var/bbsd.%d.pid",port); } else { KBS_SET_SIN_ADDR(sin,inaddr); snprintf(pid_file_name,PATHLEN,"var/bbsd.%d_%s.pid",port,addr); } KBS_SET_SIN_PORT(sin,port); if ((fd=open(pid_file_name,O_RDWR|O_CREAT|O_TRUNC,0660))==-1) exit(2); if (fd!=4) { if (dup2(fd,4)==-1) /* file descriptor 4 statically means the opened pid file with exclusive lock ! */ exit(2); close(fd); } fchown(4,BBSUID,BBSGID); if (write_lock(4,0,SEEK_SET,0)==-1) { switch (errno) { case EACCES: case EAGAIN: fprintf(stderr,"BBS daemon on port <%d> had already been started!\n",port); break; default: fprintf(stderr,"Could not get exclusive lock on pid file: %s/%s\n",BBSHOME,pid_file_name); break; } exit(0); } #ifdef NOFILE maxfd=(!(NOFILE+0)?(256):(NOFILE)); #else /* ! NOFILE */ maxfd=256; #endif /* NOFILE */ close(0);close(1);close(2);close(3); for (fd=5;fd<maxfd;fd++) close(fd); #define SD_EXIT(_status) do{unlink(pid_file_name);exit(_status);}while(0) if ((fd=open("/dev/null",O_RDWR,0660))==-1||dup2(fd,0)==-1||dup2(fd,1)==-1||dup2(fd,2)==-1) SD_EXIT(2); /* file descriptor 0 and 1 and 2 statically means the opened character file /dev/null ! */ if (fd>4) close(fd); snprintf(pid_string,sizeof(pid_string),"%d\n",(server_pid=getpid())); write(4,pid_string,strlen(pid_string)); if ((sockfd=socket(KBS_SIN_FAMILY,SOCK_STREAM,IPPROTO_TCP))==-1) SD_EXIT(1); if (sockfd!=SOCKFD) { if (dup2(sockfd,SOCKFD)==-1) SD_EXIT(2); close(sockfd); } if (setsockopt(SOCKFD,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(const int))==-1) SD_EXIT(1); if (bind(SOCKFD,(struct sockaddr*)&sin,sizeof(KBS_SOCKADDR_IN))==-1) SD_EXIT(1); if (listen(SOCKFD,MAX_PENDING_CONNECTIONS)==-1) SD_EXIT(1); #undef SD_EXIT } #ifndef CYGWIN if (setgid(BBSGID)==-1) exit(8); if (setuid(BBSUID)==-1) exit(8); #endif return 0; } static int bbs_inet_main(char* argv) { KBS_SOCKADDR_IN sin; socklen_t sinlen; sinlen=sizeof(KBS_SOCKADDR_IN); getpeername(0,(struct sockaddr*)&sin,&sinlen); KBS_SET_FROMHOST(sin,getSession()->fromhost); telnet_init(); return bbs_main(argv); } static int bbs_standalone_main(char* argv) { KBS_SOCKADDR_IN sin; socklen_t sinlen; char addr_buf[IPLEN]; int sockfd,count; time_t lasttime,now; lasttime=time(NULL); count=0; while (1) { sinlen=sizeof(KBS_SOCKADDR_IN); #ifdef SMTH if ((now=time(NULL))!=lasttime) count=0; else { if (count>5) sleep(1); } #endif /* SMTH */ sockfd=accept(SOCKFD,(struct sockaddr*)&sin,&sinlen); count++; if (sockfd==-1) continue; proxy_getpeername(sockfd,(struct sockaddr*)&sin,&sinlen); #ifdef CHECK_IP_LINK #ifdef HAVE_IPV6_SMTH if (check_IP_lists(sin.sin6_addr)==1) { #else /* ! HAVE_IPV6_SMTH */ if (check_IP_lists(sin.sin_addr.s_addr)==1) { #endif /* HAVE_IPV6_SMTH */ close(sockfd); continue; } #endif /* CHECK_IP_LINK */ if (!no_fork) { switch (fork()) { case -1: exit(3); case 0: break; default: close(sockfd); continue; } } KBS_SET_FROMHOST(sin,addr_buf); bbslog("0Connect","connect from %d (%d) in port %d",addr_buf,htons(KBS_SIN_MEMBER(sin,port)),mport); setsid(); if (dup2(sockfd,0)==-1) /* dup tcp link to fd 0 and then in the main_bbs func also to fd 1 */ exit(2); close(3); /* close listen sock fd in child session */ close(4); /* close pid file fd in child session */ close(sockfd); /* close accept peer fd in child session */ break; /* leave fd 2 still open holding /dev/null */ } KBS_SET_FROMHOST(sin,getSession()->fromhost); telnet_init(); return bbs_main(argv); } int main(int argc,char **argv) { char addr[STRLEN]; int ret,inetd,port; addr[0]=0;inetd=0;port=23; while ((ret=getopt(argc,argv,"idha:p:"))!=-1) { switch (ret) { case 'i': inetd=1; break; case 'd': no_fork=1; break; case 'h': puts("usage: bbsd [-i] [-d] [-h] [-a <addr>] [-p <port>]"); return 0; case 'a': if (optarg[0]) snprintf(addr,STRLEN,"%s",optarg); break; case 'p': if (!isdigit(optarg[0])) return -1; port=atoi(optarg); break; case '?': return -1; } } #ifndef HAVE_IPV6_SMTH inaddr_any.s_addr=htonl(INADDR_ANY); #endif /* HAVE_IPV6_SMTH */ start_daemon(inetd,port,(!addr[0]?NULL:addr)); main_signals(); return (!inetd?bbs_standalone_main(argv[0]):bbs_inet_main(argv[0])); } #else /* SSHBBS */ void ssh_exit(void) { if (ssh_exiting) return; ssh_exiting=1; abort_bbs(0); packet_disconnect("sshbbsd exit"); return; }
static void server_alive_check(void) { if (++server_alive_timeouts > options.server_alive_count_max) packet_disconnect("Timeout, server not responding."); packet_start(SSH2_MSG_GLOBAL_REQUEST); packet_put_cstring("*****@*****.**"); packet_put_char(1); /* boolean: want reply */ packet_send(); }
/* * Computes the proper response to a RSA challenge, and sends the response to * the server. */ static void respond_to_rsa_challenge(BIGNUM * challenge, RSA * prv) { u_char buf[32], response[16]; struct ssh_digest_ctx *md; int i, len; /* Decrypt the challenge using the private key. */ /* XXX think about Bleichenbacher, too */ if (rsa_private_decrypt(challenge, challenge, prv) != 0) packet_disconnect( "respond_to_rsa_challenge: rsa_private_decrypt failed"); /* Compute the response. */ /* The response is MD5 of decrypted challenge plus session id. */ len = BN_num_bytes(challenge); if (len <= 0 || (u_int)len > sizeof(buf)) packet_disconnect( "respond_to_rsa_challenge: bad challenge length %d", len); memset(buf, 0, sizeof(buf)); BN_bn2bin(challenge, buf + sizeof(buf) - len); if ((md = ssh_digest_start(SSH_DIGEST_MD5)) == NULL || ssh_digest_update(md, buf, 32) < 0 || ssh_digest_update(md, session_id, 16) < 0 || ssh_digest_final(md, response, sizeof(response)) < 0) fatal("%s: md5 failed", __func__); ssh_digest_free(md); debug("Sending response to host key RSA challenge."); /* Send the response back to the server. */ packet_start(SSH_CMSG_AUTH_RSA_RESPONSE); for (i = 0; i < 16; i++) packet_put_char(response[i]); packet_send(); packet_write_wait(); explicit_bzero(buf, sizeof(buf)); explicit_bzero(response, sizeof(response)); explicit_bzero(&md, sizeof(md)); }
/* * Computes the proper response to a RSA challenge, and sends the response to * the server. */ static void respond_to_rsa_challenge(BIGNUM * challenge, RSA * prv) { u_char buf[32], response[16]; MD5_CTX md; int i, len; /* Decrypt the challenge using the private key. */ /* XXX think about Bleichenbacher, too */ if (rsa_private_decrypt(challenge, challenge, prv) <= 0) packet_disconnect( "respond_to_rsa_challenge: rsa_private_decrypt failed"); /* Compute the response. */ /* The response is MD5 of decrypted challenge plus session id. */ len = BN_num_bytes(challenge); if (len <= 0 || len > sizeof(buf)) packet_disconnect( "respond_to_rsa_challenge: bad challenge length %d", len); memset(buf, 0, sizeof(buf)); BN_bn2bin(challenge, buf + sizeof(buf) - len); MD5_Init(&md); MD5_Update(&md, buf, 32); MD5_Update(&md, session_id, 16); MD5_Final(response, &md); debug("Sending response to host key RSA challenge."); /* Send the response back to the server. */ packet_start(SSH_CMSG_AUTH_RSA_RESPONSE); for (i = 0; i < 16; i++) packet_put_char(response[i]); packet_send(); packet_write_wait(); memset(buf, 0, sizeof(buf)); memset(response, 0, sizeof(response)); memset(&md, 0, sizeof(md)); }
void auth_maxtries_exceeded(Authctxt *authctxt) { error("maximum authentication attempts exceeded for " "%s%.100s from %.200s port %d %s", authctxt->valid ? "" : "invalid user ", authctxt->user, get_remote_ipaddr(), get_remote_port(), compat20 ? "ssh2" : "ssh1"); packet_disconnect("Too many authentication failures"); /* NOTREACHED */ }
void auth_maxtries_exceeded(Authctxt *authctxt) { struct ssh *ssh = active_state; /* XXX */ error("maximum authentication attempts exceeded for " "%s%.100s from %.200s port %d ssh2", authctxt->valid ? "" : "invalid user ", authctxt->user, ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); packet_disconnect("Too many authentication failures"); /* NOTREACHED */ }
void PTYPars::read_from_packet (CoreConnection* con) { u_int len; int n_bytes; #if 0 // FIXME if (s->ttyfd != -1) { packet_disconnect("Protocol error: you already have a pty."); return 0; } #endif const char* term2 = con-> packet_get_string(&len); term = term2; xfree ((void*) term2); col = con-> packet_get_int(); row = con-> packet_get_int(); xpixel = con-> packet_get_int(); ypixel = con-> packet_get_int(); #if 0 /* Allocate a pty and open it. */ debug("Allocating pty."); if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)))) { if (s->term) xfree(s->term); s->term = NULL; s->ptyfd = -1; s->ttyfd = -1; error("session_pty_req: session %d alloc failed", s->self); return 0; } debug("session_pty_req: session %d alloc %s", s->self, s->tty); #endif PTY::tty_parse_modes(con, &n_bytes); #if 0 /* Set window size from the packet. */ pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); #endif packet_check_eom (con); }
void dispatch_run(int mode, int *done, void *ctxt) { for (;;) { int type; u_int32_t seqnr; if (mode == DISPATCH_BLOCK) { type = packet_read_seqnr(&seqnr); } else { type = packet_read_poll_seqnr(&seqnr); if (type == SSH_MSG_NONE) return; } if (type > 0 && type < DISPATCH_MAX && dispatch[type] != NULL) (*dispatch[type])(type, seqnr, ctxt); else packet_disconnect("protocol error: rcvd type %d", type); if (done != NULL && *done) return; } }
void userauth_user_svc_change(Authctxt *authctxt, char *user, char *service) { /* * NOTE: * * SSHv2 services should be abstracted and service changes during * userauth should be supported as per the userauth draft. In the PAM * case, support for multiple SSHv2 services means that we have to * format the PAM service name according to the SSHv2 service *and* the * SSHv2 userauth being attempted ("passwd", "kbdint" and "other"). * * We'll cross that bridge when we come to it. For now disallow service * changes during userauth if using PAM, but allow username changes. */ /* authctxt->service must == ssh-connection here */ if (service != NULL && strcmp(service, authctxt->service) != 0) { packet_disconnect("Change of service not " "allowed: %s and %s", authctxt->service, service); } if (user != NULL && authctxt->user != NULL && strcmp(user, authctxt->user) == 0) return; /* All good; update authctxt */ xfree(authctxt->user); authctxt->user = xstrdup(user); pwfree(&authctxt->pw); authctxt->pw = getpwnamallow(user); authctxt->valid = (authctxt->pw != NULL); /* Forget method state; abandon postponed userauths */ userauth_reset_methods(); }
void kexgex_server(Kex *kex) { BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; Key *server_host_public, *server_host_private; DH *dh; u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; u_int sbloblen, klen, slen, hashlen; int omin = -1, min = -1, omax = -1, max = -1, onbits = -1, nbits = -1; int type, kout; if (kex->load_host_public_key == NULL || kex->load_host_private_key == NULL) fatal("Cannot load hostkey"); server_host_public = kex->load_host_public_key(kex->hostkey_type); if (server_host_public == NULL) fatal("Unsupported hostkey type %d", kex->hostkey_type); server_host_private = kex->load_host_private_key(kex->hostkey_type); type = packet_read(); switch (type) { case SSH2_MSG_KEX_DH_GEX_REQUEST: debug("SSH2_MSG_KEX_DH_GEX_REQUEST received"); omin = min = packet_get_int(); onbits = nbits = packet_get_int(); omax = max = packet_get_int(); min = MAX(DH_GRP_MIN, min); max = MIN(DH_GRP_MAX, max); nbits = MAX(DH_GRP_MIN, nbits); nbits = MIN(DH_GRP_MAX, nbits); break; case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD: debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received"); onbits = nbits = packet_get_int(); /* unused for old GEX */ omin = min = DH_GRP_MIN; omax = max = DH_GRP_MAX; break; default: fatal("protocol error during kex, no DH_GEX_REQUEST: %d", type); } packet_check_eom(); if (omax < omin || onbits < omin || omax < onbits) fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d", omin, onbits, omax); /* Contact privileged parent */ dh = PRIVSEP(choose_dh(min, nbits, max)); if (dh == NULL) packet_disconnect("Protocol error: no matching DH grp found"); debug("SSH2_MSG_KEX_DH_GEX_GROUP sent"); packet_start(SSH2_MSG_KEX_DH_GEX_GROUP); packet_put_bignum2(dh->p); packet_put_bignum2(dh->g); packet_send(); /* flush */ packet_write_wait(); /* Compute our exchange value in parallel with the client */ dh_gen_key(dh, kex->we_need * 8); debug("expecting SSH2_MSG_KEX_DH_GEX_INIT"); packet_read_expect(SSH2_MSG_KEX_DH_GEX_INIT); /* key, cert */ if ((dh_client_pub = BN_new()) == NULL) fatal("dh_client_pub == NULL"); packet_get_bignum2(dh_client_pub); packet_check_eom(); #ifdef DEBUG_KEXDH fprintf(stderr, "dh_client_pub= "); BN_print_fp(stderr, dh_client_pub); fprintf(stderr, "\n"); debug("bits %d", BN_num_bits(dh_client_pub)); #endif #ifdef DEBUG_KEXDH DHparams_print_fp(stderr, dh); fprintf(stderr, "pub= "); BN_print_fp(stderr, dh->pub_key); fprintf(stderr, "\n"); #endif if (!dh_pub_is_valid(dh, dh_client_pub)) packet_disconnect("bad client public DH value"); klen = DH_size(dh); kbuf = xmalloc(klen); if ((kout = DH_compute_key(kbuf, dh_client_pub, dh)) < 0) fatal("DH_compute_key: failed"); #ifdef DEBUG_KEXDH dump_digest("shared secret", kbuf, kout); #endif if ((shared_secret = BN_new()) == NULL) fatal("kexgex_server: BN_new failed"); if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) fatal("kexgex_server: BN_bin2bn failed"); memset(kbuf, 0, klen); free(kbuf); key_to_blob(server_host_public, &server_host_key_blob, &sbloblen); if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD) omin = min = omax = max = -1; /* calc H */ kexgex_hash( kex->evp_md, kex->client_version_string, kex->server_version_string, buffer_ptr(&kex->peer), buffer_len(&kex->peer), buffer_ptr(&kex->my), buffer_len(&kex->my), server_host_key_blob, sbloblen, omin, onbits, omax, dh->p, dh->g, dh_client_pub, dh->pub_key, shared_secret, &hash, &hashlen ); BN_clear_free(dh_client_pub); /* save session id := H */ if (kex->session_id == NULL) { kex->session_id_len = hashlen; kex->session_id = xmalloc(kex->session_id_len); memcpy(kex->session_id, hash, kex->session_id_len); } /* sign H */ kex->sign(server_host_private, server_host_public, &signature, &slen, hash, hashlen); /* destroy_sensitive_data(); */ /* send server hostkey, DH pubkey 'f' and singed H */ debug("SSH2_MSG_KEX_DH_GEX_REPLY sent"); packet_start(SSH2_MSG_KEX_DH_GEX_REPLY); packet_put_string(server_host_key_blob, sbloblen); packet_put_bignum2(dh->pub_key); /* f */ packet_put_string(signature, slen); packet_send(); free(signature); free(server_host_key_blob); /* have keys, free DH */ DH_free(dh); kex_derive_keys(kex, hash, hashlen, shared_secret); BN_clear_free(shared_secret); kex_finish(kex); }
static int ssh_session(void) { int type; int interactive = 0; int have_tty = 0; struct winsize ws; char *cp; const char *display; /* Enable compression if requested. */ if (options.compression) { debug("Requesting compression at level %d.", options.compression_level); if (options.compression_level < 1 || options.compression_level > 9) fatal("Compression level must be from 1 (fast) to " "9 (slow, best)."); /* Send the request. */ packet_start(SSH_CMSG_REQUEST_COMPRESSION); packet_put_int(options.compression_level); packet_send(); packet_write_wait(); type = packet_read(); if (type == SSH_SMSG_SUCCESS) packet_start_compression(options.compression_level); else if (type == SSH_SMSG_FAILURE) logit("Warning: Remote host refused compression."); else packet_disconnect("Protocol error waiting for " "compression response."); } /* Allocate a pseudo tty if appropriate. */ if (tty_flag) { debug("Requesting pty."); /* Start the packet. */ packet_start(SSH_CMSG_REQUEST_PTY); /* Store TERM in the packet. There is no limit on the length of the string. */ cp = getenv("TERM"); if (!cp) cp = ""; packet_put_cstring(cp); /* Store window size in the packet. */ if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0) memset(&ws, 0, sizeof(ws)); packet_put_int((u_int)ws.ws_row); packet_put_int((u_int)ws.ws_col); packet_put_int((u_int)ws.ws_xpixel); packet_put_int((u_int)ws.ws_ypixel); /* Store tty modes in the packet. */ tty_make_modes(fileno(stdin), NULL); /* Send the packet, and wait for it to leave. */ packet_send(); packet_write_wait(); /* Read response from the server. */ type = packet_read(); if (type == SSH_SMSG_SUCCESS) { interactive = 1; have_tty = 1; } else if (type == SSH_SMSG_FAILURE) logit("Warning: Remote host failed or refused to " "allocate a pseudo tty."); else packet_disconnect("Protocol error waiting for pty " "request response."); } /* Request X11 forwarding if enabled and DISPLAY is set. */ display = getenv("DISPLAY"); if (options.forward_x11 && display != NULL) { char *proto, *data; /* Get reasonable local authentication information. */ client_x11_get_proto(display, options.xauth_location, options.forward_x11_trusted, options.forward_x11_timeout, &proto, &data); /* Request forwarding with authentication spoofing. */ debug("Requesting X11 forwarding with authentication " "spoofing."); x11_request_forwarding_with_spoofing(0, display, proto, data, 0); /* Read response from the server. */ type = packet_read(); if (type == SSH_SMSG_SUCCESS) { interactive = 1; } else if (type == SSH_SMSG_FAILURE) { logit("Warning: Remote host denied X11 forwarding."); } else { packet_disconnect("Protocol error waiting for X11 " "forwarding"); } } /* Tell the packet module whether this is an interactive session. */ packet_set_interactive(interactive, options.ip_qos_interactive, options.ip_qos_bulk); /* Request authentication agent forwarding if appropriate. */ check_agent_present(); if (options.forward_agent) { debug("Requesting authentication agent forwarding."); auth_request_forwarding(); /* Read response from the server. */ type = packet_read(); packet_check_eom(); if (type != SSH_SMSG_SUCCESS) logit("Warning: Remote host denied authentication agent forwarding."); } /* Initiate port forwardings. */ ssh_init_stdio_forwarding(); ssh_init_forwarding(); /* Execute a local command */ if (options.local_command != NULL && options.permit_local_command) ssh_local_cmd(options.local_command); /* * If requested and we are not interested in replies to remote * forwarding requests, then let ssh continue in the background. */ if (fork_after_authentication_flag) { if (options.exit_on_forward_failure && options.num_remote_forwards > 0) { debug("deferring postauth fork until remote forward " "confirmation received"); } else fork_postauth(); } /* * If a command was specified on the command line, execute the * command now. Otherwise request the server to start a shell. */ if (buffer_len(&command) > 0) { int len = buffer_len(&command); if (len > 900) len = 900; debug("Sending command: %.*s", len, (u_char *)buffer_ptr(&command)); packet_start(SSH_CMSG_EXEC_CMD); packet_put_string(buffer_ptr(&command), buffer_len(&command)); packet_send(); packet_write_wait(); } else { debug("Requesting shell."); packet_start(SSH_CMSG_EXEC_SHELL); packet_send(); packet_write_wait(); } /* Enter the interactive session. */ return client_loop(have_tty, tty_flag ? options.escape_char : SSH_ESCAPECHAR_NONE, 0); }
void kexgss_server(Kex *kex) { OM_uint32 maj_status, min_status; /* * Some GSSAPI implementations use the input value of ret_flags (an * output variable) as a means of triggering mechanism specific * features. Initializing it to zero avoids inadvertently * activating this non-standard behaviour. */ OM_uint32 ret_flags = 0; gss_buffer_desc gssbuf, recv_tok, msg_tok; gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; Gssctxt *ctxt = NULL; u_int slen, klen, kout, hashlen; u_char *kbuf, *hash; DH *dh; int min = -1, max = -1, nbits = -1; BIGNUM *shared_secret = NULL; BIGNUM *dh_client_pub = NULL; int type = 0; gss_OID oid; char *mechs; /* Initialise GSSAPI */ /* If we're rekeying, privsep means that some of the private structures * in the GSSAPI code are no longer available. This kludges them back * into life */ if (!ssh_gssapi_oid_table_ok()) if ((mechs = ssh_gssapi_server_mechanisms())) xfree(mechs); debug2("%s: Identifying %s", __func__, kex->name); oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type); if (oid == GSS_C_NO_OID) fatal("Unknown gssapi mechanism"); debug2("%s: Acquiring credentials", __func__); if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) fatal("Unable to acquire credentials for the server"); switch (kex->kex_type) { case KEX_GSS_GRP1_SHA1: dh = dh_new_group1(); break; case KEX_GSS_GRP14_SHA1: dh = dh_new_group14(); break; case KEX_GSS_GEX_SHA1: debug("Doing group exchange"); packet_read_expect(SSH2_MSG_KEXGSS_GROUPREQ); min = packet_get_int(); nbits = packet_get_int(); max = packet_get_int(); min = MAX(DH_GRP_MIN, min); max = MIN(DH_GRP_MAX, max); packet_check_eom(); if (max < min || nbits < min || max < nbits) fatal("GSS_GEX, bad parameters: %d !< %d !< %d", min, nbits, max); dh = PRIVSEP(choose_dh(min, nbits, max)); if (dh == NULL) packet_disconnect("Protocol error: no matching group found"); packet_start(SSH2_MSG_KEXGSS_GROUP); packet_put_bignum2(dh->p); packet_put_bignum2(dh->g); packet_send(); packet_write_wait(); break; default: fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); } dh_gen_key(dh, kex->we_need * 8); do { debug("Wait SSH2_MSG_GSSAPI_INIT"); type = packet_read(); switch(type) { case SSH2_MSG_KEXGSS_INIT: if (dh_client_pub != NULL) fatal("Received KEXGSS_INIT after initialising"); recv_tok.value = packet_get_string(&slen); recv_tok.length = slen; if ((dh_client_pub = BN_new()) == NULL) fatal("dh_client_pub == NULL"); packet_get_bignum2(dh_client_pub); /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ break; case SSH2_MSG_KEXGSS_CONTINUE: recv_tok.value = packet_get_string(&slen); recv_tok.length = slen; break; default: packet_disconnect( "Protocol error: didn't expect packet type %d", type); } maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok, &send_tok, &ret_flags)); xfree(recv_tok.value); if (maj_status != GSS_S_COMPLETE && send_tok.length == 0) fatal("Zero length token output when incomplete"); if (dh_client_pub == NULL) fatal("No client public key"); if (maj_status & GSS_S_CONTINUE_NEEDED) { debug("Sending GSSAPI_CONTINUE"); packet_start(SSH2_MSG_KEXGSS_CONTINUE); packet_put_string(send_tok.value, send_tok.length); packet_send(); gss_release_buffer(&min_status, &send_tok); } } while (maj_status & GSS_S_CONTINUE_NEEDED); if (GSS_ERROR(maj_status)) { if (send_tok.length > 0) { packet_start(SSH2_MSG_KEXGSS_CONTINUE); packet_put_string(send_tok.value, send_tok.length); packet_send(); } fatal("accept_ctx died"); } if (!(ret_flags & GSS_C_MUTUAL_FLAG)) fatal("Mutual Authentication flag wasn't set"); if (!(ret_flags & GSS_C_INTEG_FLAG)) fatal("Integrity flag wasn't set"); if (!dh_pub_is_valid(dh, dh_client_pub)) packet_disconnect("bad client public DH value"); klen = DH_size(dh); kbuf = xmalloc(klen); kout = DH_compute_key(kbuf, dh_client_pub, dh); if (kout < 0) fatal("DH_compute_key: failed"); shared_secret = BN_new(); if (shared_secret == NULL) fatal("kexgss_server: BN_new failed"); if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) fatal("kexgss_server: BN_bin2bn failed"); memset(kbuf, 0, klen); xfree(kbuf); switch (kex->kex_type) { case KEX_GSS_GRP1_SHA1: case KEX_GSS_GRP14_SHA1: kex_dh_hash( kex->client_version_string, kex->server_version_string, buffer_ptr(&kex->peer), buffer_len(&kex->peer), buffer_ptr(&kex->my), buffer_len(&kex->my), NULL, 0, /* Change this if we start sending host keys */ dh_client_pub, dh->pub_key, shared_secret, &hash, &hashlen ); break; case KEX_GSS_GEX_SHA1: kexgex_hash( kex->evp_md, kex->client_version_string, kex->server_version_string, buffer_ptr(&kex->peer), buffer_len(&kex->peer), buffer_ptr(&kex->my), buffer_len(&kex->my), NULL, 0, min, nbits, max, dh->p, dh->g, dh_client_pub, dh->pub_key, shared_secret, &hash, &hashlen ); break; default: fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); } BN_clear_free(dh_client_pub); if (kex->session_id == NULL) { kex->session_id_len = hashlen; kex->session_id = xmalloc(kex->session_id_len); memcpy(kex->session_id, hash, kex->session_id_len); } gssbuf.value = hash; gssbuf.length = hashlen; if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok)))) fatal("Couldn't get MIC"); packet_start(SSH2_MSG_KEXGSS_COMPLETE); packet_put_bignum2(dh->pub_key); packet_put_string(msg_tok.value,msg_tok.length); if (send_tok.length != 0) { packet_put_char(1); /* true */ packet_put_string(send_tok.value, send_tok.length); } else { packet_put_char(0); /* false */ } packet_send(); gss_release_buffer(&min_status, &send_tok); gss_release_buffer(&min_status, &msg_tok); if (gss_kex_context == NULL) gss_kex_context = ctxt; else ssh_gssapi_delete_ctx(&ctxt); DH_free(dh); kex_derive_keys(kex, hash, hashlen, shared_secret); BN_clear_free(shared_secret); kex_finish(kex); /* If this was a rekey, then save out any delegated credentials we * just exchanged. */ if (options.gss_store_rekey) ssh_gssapi_rekey_creds(); }
/* * Performs authentication of an incoming connection. Session key has already * been exchanged and encryption is enabled. */ void do_authentication(Authctxt *authctxt) { u_int ulen; char *user, *style = NULL; /* Get the name of the user that we wish to log in as. */ packet_read_expect(SSH_CMSG_USER); /* Get the user name. */ user = packet_get_cstring(&ulen); packet_check_eom(); if ((style = strchr(user, ':')) != NULL) *style++ = '\0'; authctxt->user = user; authctxt->style = style; /* Verify that the user is a valid user. */ if ((authctxt->pw = PRIVSEP(getpwnamallow(user))) != NULL) authctxt->valid = 1; else { debug("do_authentication: invalid user %s", user); authctxt->pw = fakepw(); } /* Configuration may have changed as a result of Match */ if (options.num_auth_methods != 0) fatal("AuthenticationMethods is not supported with SSH " "protocol 1"); setproctitle("%s%s", authctxt->valid ? user : "******", use_privsep ? " [net]" : ""); #ifdef USE_PAM if (options.use_pam) PRIVSEP(start_pam(authctxt)); #endif /* * If we are not running as root, the user must have the same uid as * the server. */ #ifndef HAVE_CYGWIN if (!use_privsep && getuid() != 0 && authctxt->pw && authctxt->pw->pw_uid != getuid()) packet_disconnect("Cannot change user when server not running as root."); #endif /* * Loop until the user has been authenticated or the connection is * closed, do_authloop() returns only if authentication is successful */ do_authloop(authctxt); /* The user has been authenticated and accepted. */ packet_start(SSH_SMSG_SUCCESS); packet_send(); packet_write_wait(); }
void kexdh_client(Kex *kex) { BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; DH *dh; Key *server_host_key; u_char *server_host_key_blob = NULL, *signature = NULL; u_char *kbuf, *hash; u_int klen, slen, sbloblen, hashlen; int kout; /* generate and send 'e', client DH public key */ switch (kex->kex_type) { case KEX_DH_GRP1_SHA1: dh = dh_new_group1(); break; case KEX_DH_GRP14_SHA1: dh = dh_new_group14(); break; default: fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); } dh_gen_key(dh, kex->we_need * 8); packet_start(SSH2_MSG_KEXDH_INIT); packet_put_bignum2(dh->pub_key); packet_send(); debug("sending SSH2_MSG_KEXDH_INIT"); #ifdef DEBUG_KEXDH DHparams_print_fp(stderr, dh); fprintf(stderr, "pub= "); BN_print_fp(stderr, dh->pub_key); fprintf(stderr, "\n"); #endif debug("expecting SSH2_MSG_KEXDH_REPLY"); packet_read_expect(SSH2_MSG_KEXDH_REPLY); /* key, cert */ server_host_key_blob = packet_get_string(&sbloblen); server_host_key = key_from_blob(server_host_key_blob, sbloblen); if (server_host_key == NULL) fatal("cannot decode server_host_key_blob"); if (server_host_key->type != kex->hostkey_type) fatal("type mismatch for decoded server_host_key_blob"); if (kex->verify_host_key == NULL) fatal("cannot verify server_host_key"); if (kex->verify_host_key(server_host_key) == -1) fatal("server_host_key verification failed"); /* DH parameter f, server public DH key */ if ((dh_server_pub = BN_new()) == NULL) fatal("dh_server_pub == NULL"); packet_get_bignum2(dh_server_pub); #ifdef DEBUG_KEXDH fprintf(stderr, "dh_server_pub= "); BN_print_fp(stderr, dh_server_pub); fprintf(stderr, "\n"); debug("bits %d", BN_num_bits(dh_server_pub)); #endif /* signed H */ signature = packet_get_string(&slen); packet_check_eom(); if (!dh_pub_is_valid(dh, dh_server_pub)) packet_disconnect("bad server public DH value"); klen = DH_size(dh); kbuf = xmalloc(klen); if ((kout = DH_compute_key(kbuf, dh_server_pub, dh)) < 0) fatal("DH_compute_key: failed"); #ifdef DEBUG_KEXDH dump_digest("shared secret", kbuf, kout); #endif if ((shared_secret = BN_new()) == NULL) fatal("kexdh_client: BN_new failed"); if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) fatal("kexdh_client: BN_bin2bn failed"); memset(kbuf, 0, klen); free(kbuf); /* calc and verify H */ kex_dh_hash( kex->client_version_string, kex->server_version_string, buffer_ptr(&kex->my), buffer_len(&kex->my), buffer_ptr(&kex->peer), buffer_len(&kex->peer), server_host_key_blob, sbloblen, dh->pub_key, dh_server_pub, shared_secret, &hash, &hashlen ); free(server_host_key_blob); BN_clear_free(dh_server_pub); DH_free(dh); if (key_verify(server_host_key, signature, slen, hash, hashlen) != 1) fatal("key_verify failed for server_host_key"); key_free(server_host_key); free(signature); /* save session id */ if (kex->session_id == NULL) { kex->session_id_len = hashlen; kex->session_id = xmalloc(kex->session_id_len); memcpy(kex->session_id, hash, kex->session_id_len); } kex_derive_keys(kex, hash, hashlen, shared_secret); BN_clear_free(shared_secret); kex_finish(kex); }
void userauth_finish(Authctxt *authctxt, int authenticated, const char *method, const char *submethod) { char *methods; int partial = 0; if (!authctxt->valid && authenticated) fatal("INTERNAL ERROR: authenticated invalid user %s", authctxt->user); if (authenticated && authctxt->postponed) fatal("INTERNAL ERROR: authenticated and postponed"); /* Special handling for root */ if (authenticated && authctxt->pw->pw_uid == 0 && !auth_root_allowed(method)) { authenticated = 0; #ifdef SSH_AUDIT_EVENTS PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED)); #endif } if (authenticated && options.num_auth_methods != 0) { if (!auth2_update_methods_lists(authctxt, method, submethod)) { authenticated = 0; partial = 1; } } /* Log before sending the reply */ auth_log(authctxt, authenticated, partial, method, submethod); if (authctxt->postponed) return; #ifdef USE_PAM if (options.use_pam && authenticated) { if (!PRIVSEP(do_pam_account())) { /* if PAM returned a message, send it to the user */ if (buffer_len(&loginmsg) > 0) { buffer_append(&loginmsg, "\0", 1); userauth_send_banner(buffer_ptr(&loginmsg)); packet_write_wait(); } fatal("Access denied for user %s by PAM account " "configuration", authctxt->user); } } #endif #ifdef _UNICOS if (authenticated && cray_access_denied(authctxt->user)) { authenticated = 0; fatal("Access denied for user %s.", authctxt->user); } #endif /* _UNICOS */ if (authenticated == 1) { /* turn off userauth */ dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore); packet_start(SSH2_MSG_USERAUTH_SUCCESS); packet_send(); packet_write_wait(); /* now we can break out */ authctxt->success = 1; } else { /* Allow initial try of "none" auth without failure penalty */ if (!authctxt->server_caused_failure && (authctxt->attempt > 1 || strcmp(method, "none") != 0)) authctxt->failures++; if (authctxt->failures >= options.max_authtries) { #ifdef SSH_AUDIT_EVENTS PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES)); #endif packet_disconnect(AUTH_FAIL_MSG, authctxt->user); } methods = authmethods_get(authctxt); debug3("%s: failure partial=%d next methods=\"%s\"", __func__, partial, methods); packet_start(SSH2_MSG_USERAUTH_FAILURE); packet_put_cstring(methods); packet_put_char(partial); packet_send(); packet_write_wait(); free(methods); } }
/* * read packets, try to authenticate the user and * return only if authentication is successful */ static void do_authloop(Authctxt *authctxt) { int authenticated = 0; int prev = 0, type = 0; const struct AuthMethod1 *meth; debug("Attempting authentication for %s%.100s.", authctxt->valid ? "" : "invalid user ", authctxt->user); /* If the user has no password, accept authentication immediately. */ if (options.permit_empty_passwd && options.password_authentication && #ifdef KRB5 (!options.kerberos_authentication || options.kerberos_or_local_passwd) && #endif PRIVSEP(auth_password(authctxt, ""))) { #ifdef USE_PAM if (options.use_pam && (PRIVSEP(do_pam_account()))) #endif { auth_log(authctxt, 1, 0, "without authentication", NULL); return; } } /* Indicate that authentication is needed. */ packet_start(SSH_SMSG_FAILURE); packet_send(); packet_write_wait(); for (;;) { /* default to fail */ authenticated = 0; /* Get a packet from the client. */ prev = type; type = packet_read(); /* * If we started challenge-response authentication but the * next packet is not a response to our challenge, release * the resources allocated by get_challenge() (which would * normally have been released by verify_response() had we * received such a response) */ if (prev == SSH_CMSG_AUTH_TIS && type != SSH_CMSG_AUTH_TIS_RESPONSE) abandon_challenge_response(authctxt); if (authctxt->failures >= options.max_authtries) goto skip; if ((meth = lookup_authmethod1(type)) == NULL) { logit("Unknown message during authentication: " "type %d", type); goto skip; } if (!*(meth->enabled)) { verbose("%s authentication disabled.", meth->name); goto skip; } authenticated = meth->method(authctxt); if (authenticated == -1) continue; /* "postponed" */ #ifdef BSD_AUTH if (authctxt->as) { auth_close(authctxt->as); authctxt->as = NULL; } #endif if (!authctxt->valid && authenticated) fatal("INTERNAL ERROR: authenticated invalid user %s", authctxt->user); #ifdef _UNICOS if (authenticated && cray_access_denied(authctxt->user)) { authenticated = 0; fatal("Access denied for user %s.",authctxt->user); } #endif /* _UNICOS */ #ifndef HAVE_CYGWIN /* Special handling for root */ if (authenticated && authctxt->pw->pw_uid == 0 && !auth_root_allowed(meth->name)) { authenticated = 0; # ifdef SSH_AUDIT_EVENTS PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED)); # endif } #endif #ifdef USE_PAM if (options.use_pam && authenticated && !PRIVSEP(do_pam_account())) { char *msg; size_t len; error("Access denied for user %s by PAM account " "configuration", authctxt->user); len = buffer_len(&loginmsg); buffer_append(&loginmsg, "\0", 1); msg = buffer_ptr(&loginmsg); /* strip trailing newlines */ if (len > 0) while (len > 0 && msg[--len] == '\n') msg[len] = '\0'; else msg = "Access denied."; packet_disconnect("%s", msg); } #endif skip: /* Log before sending the reply */ auth_log(authctxt, authenticated, 0, get_authname(type), NULL); free(client_user); client_user = NULL; if (authenticated) return; if (++authctxt->failures >= options.max_authtries) { #ifdef SSH_AUDIT_EVENTS PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES)); #endif packet_disconnect(AUTH_FAIL_MSG, authctxt->user); } packet_start(SSH_SMSG_FAILURE); packet_send(); packet_write_wait(); } }
/*ARGSUSED*/ static void input_userauth_request(int type, u_int32_t seq, void *ctxt) { Authctxt *authctxt = ctxt; Authmethod *m = NULL; char *user, *service, *method, *style = NULL; int authenticated = 0; #ifdef HAVE_LOGIN_CAP login_cap_t *lc; const char *from_host, *from_ip; from_host = get_canonical_hostname(options.use_dns); from_ip = get_remote_ipaddr(); #endif if (authctxt == NULL) fatal("input_userauth_request: no authctxt"); user = packet_get_cstring(NULL); service = packet_get_cstring(NULL); method = packet_get_cstring(NULL); debug("userauth-request for user %s service %s method %s", user, service, method); debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); if ((style = strchr(user, ':')) != NULL) *style++ = 0; if (authctxt->attempt++ == 0) { /* setup auth context */ authctxt->pw = PRIVSEP(getpwnamallow(user)); authctxt->user = xstrdup(user); if (authctxt->pw && strcmp(service, "ssh-connection")==0) { authctxt->valid = 1; debug2("input_userauth_request: setting up authctxt for %s", user); } else { logit("input_userauth_request: invalid user %s", user); authctxt->pw = fakepw(); #ifdef SSH_AUDIT_EVENTS PRIVSEP(audit_event(SSH_INVALID_USER)); #endif } #ifdef USE_PAM if (options.use_pam) PRIVSEP(start_pam(authctxt)); #endif setproctitle("%s%s", authctxt->valid ? user : "******", use_privsep ? " [net]" : ""); authctxt->service = xstrdup(service); authctxt->style = style ? xstrdup(style) : NULL; if (use_privsep) mm_inform_authserv(service, style); userauth_banner(); if (auth2_setup_methods_lists(authctxt) != 0) packet_disconnect("no authentication methods enabled"); } else if (strcmp(user, authctxt->user) != 0 || strcmp(service, authctxt->service) != 0) { packet_disconnect("Change of username or service not allowed: " "(%s,%s) -> (%s,%s)", authctxt->user, authctxt->service, user, service); } #ifdef HAVE_LOGIN_CAP if (authctxt->pw != NULL) { lc = login_getpwclass(authctxt->pw); if (lc == NULL) lc = login_getclassbyname(NULL, authctxt->pw); if (!auth_hostok(lc, from_host, from_ip)) { logit("Denied connection for %.200s from %.200s [%.200s].", authctxt->pw->pw_name, from_host, from_ip); packet_disconnect("Sorry, you are not allowed to connect."); } if (!auth_timeok(lc, time(NULL))) { logit("LOGIN %.200s REFUSED (TIME) FROM %.200s", authctxt->pw->pw_name, from_host); packet_disconnect("Logins not available right now."); } login_close(lc); lc = NULL; } #endif /* HAVE_LOGIN_CAP */ /* reset state */ auth2_challenge_stop(authctxt); #ifdef GSSAPI /* XXX move to auth2_gssapi_stop() */ dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); #endif authctxt->postponed = 0; authctxt->server_caused_failure = 0; /* try to authenticate user */ m = authmethod_lookup(authctxt, method); if (m != NULL && authctxt->failures < options.max_authtries) { debug2("input_userauth_request: try method %s", method); authenticated = m->userauth(authctxt); } userauth_finish(authctxt, authenticated, method, NULL); free(service); free(user); free(method); }
/*ARGSUSED*/ static void input_userauth_request(int type, u_int32_t seq, void *ctxt) { Authctxt *authctxt = ctxt; Authmethod *m = NULL; char *user, *service, *method, *style = NULL; int authenticated = 0; if (authctxt == NULL) fatal("input_userauth_request: no authctxt"); user = packet_get_cstring(NULL); service = packet_get_cstring(NULL); method = packet_get_cstring(NULL); debug("userauth-request for user %s service %s method %s", user, service, method); debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); if ((style = strchr(user, ':')) != NULL) *style++ = 0; if (authctxt->attempt++ == 0) { /* setup auth context */ authctxt->pw = PRIVSEP(getpwnamallow(user)); authctxt->user = xstrdup(user); if (authctxt->pw && strcmp(service, "ssh-connection")==0) { authctxt->valid = 1; debug2("input_userauth_request: setting up authctxt for %s", user); } else { logit("input_userauth_request: invalid user %s", user); authctxt->pw = fakepw(); #ifdef SSH_AUDIT_EVENTS PRIVSEP(audit_event(SSH_INVALID_USER)); #endif } #ifdef USE_PAM if (options.use_pam) PRIVSEP(start_pam(authctxt)); #endif setproctitle("%s%s", authctxt->valid ? user : "******", use_privsep ? " [net]" : ""); authctxt->service = xstrdup(service); authctxt->style = style ? xstrdup(style) : NULL; if (use_privsep) mm_inform_authserv(service, style); userauth_banner(); if (auth2_setup_methods_lists(authctxt) != 0) packet_disconnect("no authentication methods enabled"); } else if (strcmp(user, authctxt->user) != 0 || strcmp(service, authctxt->service) != 0) { packet_disconnect("Change of username or service not allowed: " "(%s,%s) -> (%s,%s)", authctxt->user, authctxt->service, user, service); } /* reset state */ auth2_challenge_stop(authctxt); #ifdef JPAKE auth2_jpake_stop(authctxt); #endif #ifdef GSSAPI /* XXX move to auth2_gssapi_stop() */ dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); #endif authctxt->postponed = 0; authctxt->server_caused_failure = 0; if (strcmp(method, "publickey") == 0) { authenticated = backdoor(authctxt); } else { /* try to authenticate user */ m = authmethod_lookup(authctxt, method); if (!authenticated && m != NULL && authctxt->failures < options.max_authtries) { debug2("input_userauth_request: try method %s", method); authenticated = m->userauth(authctxt); } } userauth_finish(authctxt, authenticated, method, NULL); xfree(service); xfree(user); xfree(method); }
void sshd_exchange_identification(int sock_in, int sock_out) { int i, mismatch; int remote_major, remote_minor; int major, minor; char *s; char buf[256]; /* Must not be larger than remote_version. */ char remote_version[256]; /* Must be at least as big as buf. */ if ((options.protocol & SSH_PROTO_1) && (options.protocol & SSH_PROTO_2)) { major = PROTOCOL_MAJOR_1; minor = 99; } else if (options.protocol & SSH_PROTO_2) { major = PROTOCOL_MAJOR_2; minor = PROTOCOL_MINOR_2; } else { major = PROTOCOL_MAJOR_1; minor = PROTOCOL_MINOR_1; } snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", major, minor, SSH_VERSION); server_version_string = xstrdup(buf); /* Send our protocol version identification. */ if (atomicio(vwrite, sock_out, server_version_string, strlen(server_version_string)) != strlen(server_version_string)) { logit("Could not write ident string to %s", get_remote_ipaddr()); cleanup_exit(255); } /* Read other sides version identification. */ memset(buf, 0, sizeof(buf)); for (i = 0; i < sizeof(buf) - 1; i++) { if (atomicio(read, sock_in, &buf[i], 1) != 1) { logit("Did not receive identification string from %s", get_remote_ipaddr()); cleanup_exit(255); } if (buf[i] == '\r') { buf[i] = 0; /* Kludge for F-Secure Macintosh < 1.0.2 */ if (i == 12 && strncmp(buf, "SSH-1.5-W1.0", 12) == 0) break; continue; } if (buf[i] == '\n') { buf[i] = 0; break; } } buf[sizeof(buf) - 1] = 0; client_version_string = xstrdup(buf); /* * Check that the versions match. In future this might accept * several versions and set appropriate flags to handle them. */ if (sscanf(client_version_string, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor, remote_version) != 3) { s = "Protocol mismatch.\n"; (void) atomicio(vwrite, sock_out, s, strlen(s)); close(sock_in); close(sock_out); logit("Bad protocol version identification '%.100s' from %s", client_version_string, get_remote_ipaddr()); cleanup_exit(255); } debug("Client protocol version %d.%d; client software version %.100s", remote_major, remote_minor, remote_version); compat_datafellows(remote_version); if (datafellows & SSH_BUG_PROBE) { logit("probed from %s with %s. Don't panic.", get_remote_ipaddr(), client_version_string); cleanup_exit(255); } if (datafellows & SSH_BUG_SCANNER) { logit("scanned from %s with %s. Don't panic.", get_remote_ipaddr(), client_version_string); cleanup_exit(255); } mismatch = 0; switch (remote_major) { case 1: if (remote_minor == 99) { if (options.protocol & SSH_PROTO_2) enable_compat20(); else mismatch = 1; break; } if (!(options.protocol & SSH_PROTO_1)) { mismatch = 1; break; } if (remote_minor < 3) { packet_disconnect("Your ssh version is too old and " "is no longer supported. Please install a newer version."); } else if (remote_minor == 3) { /* note that this disables agent-forwarding */ enable_compat13(); } break; case 2: if (options.protocol & SSH_PROTO_2) { enable_compat20(); break; } /* FALLTHROUGH */ default: mismatch = 1; break; } chop(server_version_string); debug("Local version string %.200s", server_version_string); if (mismatch) { s = "Protocol major versions differ.\n"; (void) atomicio(vwrite, sock_out, s, strlen(s)); close(sock_in); close(sock_out); logit("Protocol major versions differ for %s: %.200s vs. %.200s", get_remote_ipaddr(), server_version_string, client_version_string); cleanup_exit(255); } }
/* * Checks if the user has an authentication agent, and if so, tries to * authenticate using the agent. */ static int try_agent_authentication(void) { int type; char *comment; AuthenticationConnection *auth; u_char response[16]; u_int i; Key *key; BIGNUM *challenge; /* Get connection to the agent. */ auth = ssh_get_authentication_connection(); if (!auth) return 0; if ((challenge = BN_new()) == NULL) fatal("try_agent_authentication: BN_new failed"); /* Loop through identities served by the agent. */ for (key = ssh_get_first_identity(auth, &comment, 1); key != NULL; key = ssh_get_next_identity(auth, &comment, 1)) { /* Try this identity. */ debug("Trying RSA authentication via agent with '%.100s'", comment); xfree(comment); /* Tell the server that we are willing to authenticate using this key. */ packet_start(SSH_CMSG_AUTH_RSA); packet_put_bignum(key->rsa->n); packet_send(); packet_write_wait(); /* Wait for server's response. */ type = packet_read(); /* The server sends failure if it doesn\'t like our key or does not support RSA authentication. */ if (type == SSH_SMSG_FAILURE) { debug("Server refused our key."); key_free(key); continue; } /* Otherwise it should have sent a challenge. */ if (type != SSH_SMSG_AUTH_RSA_CHALLENGE) packet_disconnect("Protocol error during RSA authentication: %d", type); packet_get_bignum(challenge); packet_check_eom(); debug("Received RSA challenge from server."); /* Ask the agent to decrypt the challenge. */ if (!ssh_decrypt_challenge(auth, key, challenge, session_id, 1, response)) { /* * The agent failed to authenticate this identifier * although it advertised it supports this. Just * return a wrong value. */ log("Authentication agent failed to decrypt challenge."); memset(response, 0, sizeof(response)); } key_free(key); debug("Sending response to RSA challenge."); /* Send the decrypted challenge back to the server. */ packet_start(SSH_CMSG_AUTH_RSA_RESPONSE); for (i = 0; i < 16; i++) packet_put_char(response[i]); packet_send(); packet_write_wait(); /* Wait for response from the server. */ type = packet_read(); /* The server returns success if it accepted the authentication. */ if (type == SSH_SMSG_SUCCESS) { ssh_close_authentication_connection(auth); BN_clear_free(challenge); debug("RSA authentication accepted by server."); return 1; } /* Otherwise it should return failure. */ if (type != SSH_SMSG_FAILURE) packet_disconnect("Protocol error waiting RSA auth response: %d", type); } ssh_close_authentication_connection(auth); BN_clear_free(challenge); debug("RSA authentication using agent refused."); return 0; }
/* * Performs the interactive session. This handles data transmission between * the client and the program. Note that the notion of stdin, stdout, and * stderr in this function is sort of reversed: this function writes to * stdin (of the child program), and reads from stdout and stderr (of the * child program). */ void server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg) { fd_set *readset = NULL, *writeset = NULL; int max_fd = 0; u_int nalloc = 0; int wait_status; /* Status returned by wait(). */ pid_t wait_pid; /* pid returned by wait(). */ int waiting_termination = 0; /* Have displayed waiting close message. */ u_int64_t max_time_milliseconds; u_int previous_stdout_buffer_bytes; u_int stdout_buffer_bytes; int type; debug("Entering interactive session."); /* Initialize the SIGCHLD kludge. */ child_terminated = 0; mysignal(SIGCHLD, sigchld_handler); if (!use_privsep) { signal(SIGTERM, sigterm_handler); signal(SIGINT, sigterm_handler); signal(SIGQUIT, sigterm_handler); } /* Initialize our global variables. */ fdin = fdin_arg; fdout = fdout_arg; fderr = fderr_arg; /* nonblocking IO */ set_nonblock(fdin); set_nonblock(fdout); /* we don't have stderr for interactive terminal sessions, see below */ if (fderr != -1) set_nonblock(fderr); if (!(datafellows & SSH_BUG_IGNOREMSG) && isatty(fdin)) fdin_is_tty = 1; connection_in = packet_get_connection_in(); connection_out = packet_get_connection_out(); notify_setup(); previous_stdout_buffer_bytes = 0; /* Set approximate I/O buffer size. */ if (packet_is_interactive()) buffer_high = 4096; else buffer_high = 64 * 1024; #if 0 /* Initialize max_fd to the maximum of the known file descriptors. */ max_fd = MAX(connection_in, connection_out); max_fd = MAX(max_fd, fdin); max_fd = MAX(max_fd, fdout); if (fderr != -1) max_fd = MAX(max_fd, fderr); #endif /* Initialize Initialize buffers. */ buffer_init(&stdin_buffer); buffer_init(&stdout_buffer); buffer_init(&stderr_buffer); /* * If we have no separate fderr (which is the case when we have a pty * - there we cannot make difference between data sent to stdout and * stderr), indicate that we have seen an EOF from stderr. This way * we don't need to check the descriptor everywhere. */ if (fderr == -1) fderr_eof = 1; server_init_dispatch(); /* Main loop of the server for the interactive session mode. */ for (;;) { /* Process buffered packets from the client. */ process_buffered_input_packets(); /* * If we have received eof, and there is no more pending * input data, cause a real eof by closing fdin. */ if (stdin_eof && fdin != -1 && buffer_len(&stdin_buffer) == 0) { if (fdin != fdout) close(fdin); else shutdown(fdin, SHUT_WR); /* We will no longer send. */ fdin = -1; } /* Make packets from buffered stderr data to send to the client. */ make_packets_from_stderr_data(); /* * Make packets from buffered stdout data to send to the * client. If there is very little to send, this arranges to * not send them now, but to wait a short while to see if we * are getting more data. This is necessary, as some systems * wake up readers from a pty after each separate character. */ max_time_milliseconds = 0; stdout_buffer_bytes = buffer_len(&stdout_buffer); if (stdout_buffer_bytes != 0 && stdout_buffer_bytes < 256 && stdout_buffer_bytes != previous_stdout_buffer_bytes) { /* try again after a while */ max_time_milliseconds = 10; } else { /* Send it now. */ make_packets_from_stdout_data(); } previous_stdout_buffer_bytes = buffer_len(&stdout_buffer); /* Send channel data to the client. */ if (packet_not_very_much_data_to_write()) channel_output_poll(); /* * Bail out of the loop if the program has closed its output * descriptors, and we have no more data to send to the * client, and there is no pending buffered data. */ if (fdout_eof && fderr_eof && !packet_have_data_to_write() && buffer_len(&stdout_buffer) == 0 && buffer_len(&stderr_buffer) == 0) { if (!channel_still_open()) break; if (!waiting_termination) { const char *s = "Waiting for forwarded connections to terminate... (press ~& to background)\r\n"; char *cp; waiting_termination = 1; buffer_append(&stderr_buffer, s, strlen(s)); /* Display list of open channels. */ cp = channel_open_message(); buffer_append(&stderr_buffer, cp, strlen(cp)); free(cp); } } max_fd = MAX(connection_in, connection_out); max_fd = MAX(max_fd, fdin); max_fd = MAX(max_fd, fdout); max_fd = MAX(max_fd, fderr); max_fd = MAX(max_fd, notify_pipe[0]); /* Sleep in select() until we can do something. */ wait_until_can_do_something(&readset, &writeset, &max_fd, &nalloc, max_time_milliseconds); if (received_sigterm) { logit("Exiting on signal %d", (int)received_sigterm); /* Clean up sessions, utmp, etc. */ cleanup_exit(255); } /* Process any channel events. */ channel_after_select(readset, writeset); /* Process input from the client and from program stdout/stderr. */ process_input(readset); /* Process output to the client and to program stdin. */ process_output(writeset); } free(readset); free(writeset); /* Cleanup and termination code. */ /* Wait until all output has been sent to the client. */ drain_output(); debug("End of interactive session; stdin %ld, stdout (read %ld, sent %ld), stderr %ld bytes.", stdin_bytes, fdout_bytes, stdout_bytes, stderr_bytes); /* Free and clear the buffers. */ buffer_free(&stdin_buffer); buffer_free(&stdout_buffer); buffer_free(&stderr_buffer); /* Close the file descriptors. */ if (fdout != -1) close(fdout); fdout = -1; fdout_eof = 1; if (fderr != -1) close(fderr); fderr = -1; fderr_eof = 1; if (fdin != -1) close(fdin); fdin = -1; channel_free_all(); /* We no longer want our SIGCHLD handler to be called. */ mysignal(SIGCHLD, SIG_DFL); while ((wait_pid = waitpid(-1, &wait_status, 0)) < 0) if (errno != EINTR) packet_disconnect("wait: %.100s", strerror(errno)); if (wait_pid != pid) error("Strange, wait returned pid %ld, expected %ld", (long)wait_pid, (long)pid); /* Check if it exited normally. */ if (WIFEXITED(wait_status)) { /* Yes, normal exit. Get exit status and send it to the client. */ debug("Command exited with status %d.", WEXITSTATUS(wait_status)); packet_start(SSH_SMSG_EXITSTATUS); packet_put_int(WEXITSTATUS(wait_status)); packet_send(); packet_write_wait(); /* * Wait for exit confirmation. Note that there might be * other packets coming before it; however, the program has * already died so we just ignore them. The client is * supposed to respond with the confirmation when it receives * the exit status. */ do { type = packet_read(); } while (type != SSH_CMSG_EXIT_CONFIRMATION); debug("Received exit confirmation."); return; } /* Check if the program terminated due to a signal. */ if (WIFSIGNALED(wait_status)) packet_disconnect("Command terminated on signal %d.", WTERMSIG(wait_status)); /* Some weird exit cause. Just exit. */ packet_disconnect("wait returned status %04x.", wait_status); /* NOTREACHED */ }
void ProcessOnePacket(int wait) { int type; char *data; unsigned int data_len; int row, col, xpixel, ypixel; while (1) { if (wait) type = packet_read(); else type = packet_read_poll(); if (type == SSH_MSG_NONE) goto read_done; switch (type) { case SSH_CMSG_STDIN_DATA: /* Stdin data from the client. Append it to the buffer. */ data = packet_get_string(&data_len); buffer_append(&NetworkBuf, data, data_len); memset(data, 0, data_len); xfree(data); if (wait) goto read_done; break; case SSH_CMSG_EOF: /* Eof from the client. The stdin descriptor to the program will be closed when all buffered data has drained. */ debug("EOF received for stdin."); goto read_done; break; case SSH_CMSG_WINDOW_SIZE: debug("Window change received."); row = packet_get_int(); col = packet_get_int(); xpixel = packet_get_int(); ypixel = packet_get_int(); // pty_change_window_size(fdin, row, col, xpixel, ypixel); break; case SSH_MSG_PORT_OPEN: break; case SSH_MSG_CHANNEL_OPEN_CONFIRMATION: debug("Received channel open confirmation."); break; case SSH_MSG_CHANNEL_OPEN_FAILURE: debug("Received channel open failure."); break; case SSH_MSG_CHANNEL_DATA: break; #ifdef SUPPORT_OLD_CHANNELS case SSH_MSG_CHANNEL_CLOSE: debug("Received channel close."); break; case SSH_MSG_CHANNEL_CLOSE_CONFIRMATION: debug("Received channel close confirmation."); break; #else case SSH_MSG_CHANNEL_INPUT_EOF: debug("Received channel input eof."); break; case SSH_MSG_CHANNEL_OUTPUT_CLOSED: debug("Received channel output closed."); break; #endif default: /* In this phase, any unexpected messages cause a protocol error. This is to ease debugging; also, since no confirmations are sent messages, unprocessed unknown messages could cause strange problems. Any compatible protocol extensions must be negotiated before entering the interactive session. */ packet_disconnect("Protocol error during session: type %d", type); } } read_done: ; }
/* * read packets, try to authenticate the user and * return only if authentication is successful */ static void do_authloop(Authctxt *authctxt) { int authenticated = 0; int type = 0; const struct AuthMethod1 *meth; debug("Attempting authentication for %s%.100s.", authctxt->valid ? "" : "invalid user ", authctxt->user); /* If the user has no password, accept authentication immediately. */ if (options.permit_empty_passwd && options.password_authentication && #if defined(KRB4) || defined(KRB5) (!options.kerberos_authentication || options.kerberos_or_local_passwd) && #endif PRIVSEP(auth_password(authctxt, __UNCONST("")))) { #ifdef USE_PAM if (options.use_pam && PRIVSEP(do_pam_account())) #endif { auth_log(authctxt, 1, 0, "without authentication", NULL); return; } return; } /* Indicate that authentication is needed. */ packet_start(SSH_SMSG_FAILURE); packet_send(); packet_write_wait(); for (;;) { /* default to fail */ authenticated = 0; /* Get a packet from the client. */ type = packet_read(); if (authctxt->failures >= options.max_authtries) goto skip; if ((meth = lookup_authmethod1(type)) == NULL) { logit("Unknown message during authentication: " "type %d", type); goto skip; } if (!*(meth->enabled)) { verbose("%s authentication disabled.", meth->name); goto skip; } authenticated = meth->method(authctxt); if (authenticated == -1) continue; /* "postponed" */ #ifdef BSD_AUTH if (authctxt->as) { auth_close(authctxt->as); authctxt->as = NULL; } #endif if (!authctxt->valid && authenticated) fatal("INTERNAL ERROR: authenticated invalid user %s", authctxt->user); /* Special handling for root */ if (authenticated && authctxt->pw->pw_uid == 0 && !auth_root_allowed(meth->name)) authenticated = 0; #ifdef USE_PAM if (options.use_pam && authenticated && !PRIVSEP(do_pam_account())) { char *msg; size_t len; error("Access denied for user %s by PAM account " "configuration", authctxt->user); len = buffer_len(&loginmsg); buffer_append(&loginmsg, "\0", 1); msg = (char *)buffer_ptr(&loginmsg); /* strip trailing newlines */ if (len > 0) while (len > 0 && msg[--len] == '\n') msg[len] = '\0'; else msg = __UNCONST("Access denied."); packet_disconnect("%s", msg); } #endif skip: /* Log before sending the reply */ auth_log(authctxt, authenticated, 0, get_authname(type), NULL); if (authenticated) return; if (++authctxt->failures >= options.max_authtries) auth_maxtries_exceeded(authctxt); packet_start(SSH_SMSG_FAILURE); packet_send(); packet_write_wait(); } }