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();
}
Example #2
0
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);
}
Example #3
0
/*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);
}
Example #4
0
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 */
}
Example #6
0
/*
 * 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);
}
Example #7
0
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);
	}
}
Example #8
0
/* 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;
}
Example #9
0
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();
}
Example #10
0
/*
 * 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));
}
Example #11
0
/*
 * 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));
}
Example #12
0
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 */
}
Example #13
0
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 */
}
Example #14
0
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);
}
Example #15
0
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;
	}
}
Example #16
0
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();
}
Example #17
0
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);
}
Example #18
0
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);
}
Example #19
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();
}
Example #20
0
/*
 * 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();
}
Example #21
0
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);
}
Example #22
0
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);
	}
}
Example #23
0
/*
 * 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();
	}
}
Example #24
0
/*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);
}
Example #25
0
/*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);
}
Example #26
0
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);
	}
}
Example #27
0
/*
 * 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;
}
Example #28
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 */
}
Example #29
0
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:
  ;
}
Example #30
0
/*
 * 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();
	}
}