int STREAMFlush(STREAM *S) { STREAMWriteBytes(S,NULL,0); }
int ConnectHopSocks(STREAM *S, int SocksLevel, const char *ProxyURL, const char *Destination) { char *Tempstr=NULL; char *Token=NULL, *Host=NULL, *User=NULL, *Pass=NULL; uint8_t *ptr; uint32_t IP; const char *tptr; int result, RetVal=FALSE, val; uint8_t HostType=HT_IP4; ParseConnectDetails(ProxyURL, NULL, &Host, &Token, &User, &Pass, NULL); if (! (S->State & SS_INITIAL_CONNECT_DONE)) { val=atoi(Token); S->in_fd=TCPConnect(Host, val, 0); S->out_fd=S->in_fd; if (S->in_fd == -1) { RaiseError(0, "ConnectHopSocks", "connection to socks proxy at %s failed", ProxyURL); return(FALSE); } if (SocksLevel==CONNECT_HOP_SOCKS5) { if (! ConnectHopSocks5Auth(S, User, Pass)) { RaiseError(0, "ConnectHopSocks", "authentication to socks proxy at %s failed", ProxyURL); return(FALSE); } } } //Horrid binary protocol. Tempstr=SetStrLen(Tempstr, StrLen(User) + 20 + StrLen(Destination)); ptr=Tempstr; //version if (SocksLevel==CONNECT_HOP_SOCKS5) *ptr=5; else *ptr=4; //version number ptr++; //connection type *ptr=1; //outward connection (2 binds a port for incoming) ptr++; //Sort out destination now tptr=Destination; if (strncmp(tptr,"tcp:",4)==0) tptr+=4; tptr=GetToken(tptr,":",&Token,0); if (IsIP4Address(Token)) HostType=HT_IP4; else if (IsIP6Address(Token)) HostType=HT_IP6; else HostType=HT_DOMAIN; if (SocksLevel==CONNECT_HOP_SOCKS5) { //Socks 5 has a 'reserved' byte after the connection type *ptr=0; ptr++; *ptr=HostType; ptr++; switch (HostType) { case HT_IP4: *((uint32_t *) ptr) =StrtoIP(Token); ptr+=4; break; case HT_IP6: break; default: val=StrLen(Token); *ptr=val; ptr++; memcpy(ptr, Token, val); ptr+=val; break; } } //destination port. By a weird coincidence this is in the right place //for either socks4 or 5, despite the fact that it comes after the //host in socks5, and before the host in socks4 *((uint16_t *) ptr) =htons(atoi(tptr)); ptr+=2; if (SocksLevel==CONNECT_HOP_SOCKS4) { //destination host switch (HostType) { case HT_IP4: *((uint32_t *) ptr) =StrtoIP(Token); ptr+=4; val=StrLen(User)+1; memcpy(ptr,User,val); ptr+=val; break; default: *((uint32_t *) ptr) =StrtoIP("0.0.0.1"); ptr+=4; break; } val=StrLen(User)+1; memcpy(ptr, User, val); ptr+=val; //+1 to include terminating \0 val=StrLen(Token) +1; memcpy(ptr, Token, val); ptr+=val; } STREAMWriteBytes(S,Tempstr,(char *)ptr-Tempstr); STREAMFlush(S); Tempstr=SetStrLen(Tempstr, 32); result=STREAMReadBytes(S,Tempstr,32); if (SocksLevel==CONNECT_HOP_SOCKS5) { if ((result > 8) && (Tempstr[0]==5) && (Tempstr[1]==0)) { RetVal=TRUE; } } else { //Positive response will be 0x00 0x5a 0x00 0x00 0x00 0x00 0x00 0x00 //although only the leading two bytes (0x00 0x5a, or \0Z) matters if ((result==8) && (Tempstr[0]=='\0') && (Tempstr[1]=='Z')) { RetVal=TRUE; IP=*(uint32_t *) (Tempstr + 4); if (IP != 0) STREAMSetValue(S, "IPAddress", IPtoStr(IP)); } } if (! RetVal) RaiseError(0, "ConnectHopSocks", "socks proxy at %s refused connection to %s", ProxyURL, Destination); DestroyString(Tempstr); DestroyString(Host); DestroyString(User); DestroyString(Pass); DestroyString(Token); return(RetVal); }
void RunTelnetSession(TSession *Session) { STREAM *Local, *S; char *Tempstr=NULL; int result, fd; ListNode *Streams; struct passwd *pwent; struct group *grent; struct timeval tv; time_t Duration, Start, Now, LastActivity; time(&Start); LastActivity=Start; Streams=ListCreate(); ListAddItem(Streams,Session->S); //if '-real-user' was specified on the command-line, then this overrides //anything read from password files if (Settings.Flags & FLAG_FORCE_REALUSER) { Session->RealUser=CopyStr(Session->RealUser,Settings.RealUser); } //Get User Details before we chroot! if (StrLen(Session->RealUser)) { pwent=getpwnam(Session->RealUser); if (! pwent) { syslog(Settings.InfoLogLevel,"Failed to lookup RealUser '%s' for user '%s'",Session->RealUser,Session->User); exit(1); } Session->RealUserUID=pwent->pw_uid; Session->GroupID=pwent->pw_gid; } //if '-shell' was specified on the command-line, then this overrides //anything read from password files if (Settings.Flags & FLAG_FORCE_SHELL) { Session->Shell=CopyStr(Session->Shell,Settings.RealUser); } if (Settings.Flags & FLAG_DYNHOME) { Session->HomeDir=SessionSubstituteVars(Session->HomeDir,Settings.DynamicHomeDir,Session); Session->HomeDir=SlashTerminateDirectoryPath(Session->HomeDir); MakeDirPath(Session->HomeDir,0777); } //CD to the user's home directory if (StrLen(Session->HomeDir)) { chdir(Session->HomeDir); } DoBindMounts(Settings.BindMounts,0); //This login script allows setting up any aspects of the environment before we launch the shell. For instance it //might be used to copy files into the chroot environment before chrooting if (StrLen(Settings.LoginScript)) system(Settings.LoginScript); //LAUNCH THE SHELL FUNCTION!!! This launches the program that the telnet user is 'speaking' to. //If chhome is active, then it will be chrooted into the user's home directory PseudoTTYSpawnFunction(&fd, LaunchPtyFunc, Session, TTYFLAG_CANON | TTYFLAG_ECHO | TTYFLAG_CRLF | TTYFLAG_LFCR | TTYFLAG_IGNSIG); Local=STREAMFromFD(fd); STREAMSetTimeout(Local,0); //Might as well chroot on this side of the pipe too, unless we have a 'LogoutScript' //Logout scripts exist to allow copying stuff back out of the chroot when the session is //finished. We can't do this if we chroot this side as well as the 'shell' side if ( (! StrLen(Settings.LogoutScript)) && (Settings.Flags & FLAG_CHHOME) ) chroot("."); //DON'T SWITCH USER. NEED root TO UNBIND MOUNTS //if (setreuid(Session->RealUserUID,Session->RealUserUID) !=0) exit(1); ListAddItem(Streams,Local); Tempstr=SetStrLen(Tempstr,4096); while (1) { if (Settings.IdleTimeout) tv.tv_sec=Settings.IdleTimeout; else tv.tv_sec=3600 * 24; S=STREAMSelect(Streams,&tv); time(&Now); if (S) { if (S==Session->S) { result=TelnetReadBytes(Session->S, Tempstr, 4096, TNRB_NONBLOCK); if (result ==-1) break; STREAMWriteBytes(Local,Tempstr,result); } else { result=STREAMReadBytes(Local,Tempstr,4096); if (result < 0) break; STREAMWriteBytes(Session->S,Tempstr,result); if (result < 0) break; } if (Settings.Flags & FLAG_WINSIZE) SetWindowSize(Session->S->out_fd); LastActivity=Now; } if ((Settings.IdleTimeout > 0) && ((Now - LastActivity) > Settings.IdleTimeout)) break; } if (StrLen(Settings.LogoutScript)) system(Settings.LogoutScript); if (Settings.Flags & FLAG_UNMOUNT) UndoBindMounts(Settings.BindMounts, 0); if (Settings.Flags & FLAG_DYNHOME) rmdir(Session->HomeDir); Duration=time(NULL) - Start; syslog(Settings.InfoLogLevel,"%s@%s logged out after %d secs",Session->User,Session->ClientIP, Duration); STREAMClose(Session->S); STREAMClose(Local); DestroyString(Tempstr); }
int ConnectHopSocks5Auth(STREAM *S, const char *User, const char *Pass) { char *Tempstr=NULL; const char *p_Password; char *ptr; int result, RetVal=FALSE; uint8_t len, passlen; Tempstr=SetStrLen(Tempstr, 10); //socks5 version Tempstr[0]=5; //Number of Auth Methods (just 1, username/password) Tempstr[1]=1; //Auth method 2, username/password if (StrValid(User) || StrValid(Pass)) Tempstr[2]=SOCKS5_AUTH_PASSWD; else Tempstr[2]=SOCKS5_AUTH_NONE; STREAMWriteBytes(S,Tempstr,3); STREAMFlush(S); result=STREAMReadBytes(S,Tempstr,10); if ((result > 1) && (Tempstr[0]==5)) { // Second Byte is authentication type selected by the server switch (Tempstr[1]) { //no authentication required case 0: RetVal=TRUE; break; //gssapi case 1: break; //username/password case 2: if (Pass) { p_Password=Pass; passlen=strlen(Pass); } // must be careful with password len, as it won't be null terminated else passlen=CredsStoreLookup("", User, &p_Password); Tempstr=SetStrLen(Tempstr, StrLen(User) + passlen + 10); ptr=Tempstr; //version 1 of username/password authentication *ptr=1; ptr++; //username len=StrLen(User) & 0xFF; *ptr=len; ptr++; memcpy(ptr, User, len); ptr+=len; //password len=passlen & 0xFF; *ptr=len; ptr++; memcpy(ptr, Pass, len); ptr+=len; len=ptr-Tempstr; STREAMWriteBytes(S,Tempstr,len); //we have to flush to be sure data is sent, but this also wipes output //data buffer, which is useful given that we just sent a password STREAMFlush(S); //As this memory contained a password, we wipe it xmemset(Tempstr, 0, len); result=STREAMReadBytes(S,Tempstr,10); //two bytes reply. Byte1 is Version Byte2 is 0 for success if ((result > 1) && (Tempstr[0]==1) && (Tempstr[1]==0)) RetVal=TRUE; break; } } DestroyString(Tempstr); return(RetVal); }