int STREAMDoPostConnect(STREAM *S, int Flags) { int result=TRUE; char *ptr; struct timeval tv; if ((S->in_fd > -1) && (S->Timeout > 0) ) { tv.tv_sec=S->Timeout; tv.tv_usec=0; if (FDSelect(S->in_fd, SELECT_WRITE, &tv) <=0) { close(S->in_fd); S->in_fd=-1; S->out_fd=-1; } else if (! (Flags & CONNECT_NONBLOCK)) STREAMSetNonBlock(S, FALSE); } if (S->in_fd > -1) { S->Type=STREAM_TYPE_TCP; result=TRUE; STREAMSetFlushType(S,FLUSH_LINE,0); } //if (Flags & CONNECT_SOCKS_PROXY) result=DoSocksProxyTunnel(S); if (Flags & CONNECT_SSL) DoSSLClientNegotiation(S, Flags); ptr=GetRemoteIP(S->in_fd); if (ptr) STREAMSetValue(S,"PeerIP",ptr); return(result); }
STREAM *STREAMSpawnFunction(BASIC_FUNC Func, void *Data, const char *Config) { int to_fd, from_fd, *iptr; pid_t pid=0; STREAM *S=NULL; char *Tempstr=NULL; int Flags=0; Flags=TTYParseConfig(Config, NULL); if (Flags & TTYFLAG_PTY) { pid=PseudoTTYSpawnFunction(&to_fd, Func, Data, Flags, Config); from_fd=to_fd; } else { iptr=NULL; //if (Flags & COMMS_COMBINE_STDERR) iptr=(int *) COMMS_COMBINE_STDERR; pid=PipeSpawnFunction(&to_fd, &from_fd, iptr, Func, Data, Config); } if (pid > 0) S=STREAMFromDualFD(from_fd, to_fd); if (S) { STREAMSetFlushType(S,FLUSH_LINE,0,0); Tempstr=FormatStr(Tempstr,"%d",pid); STREAMSetValue(S,"PeerPID",Tempstr); S->Type=STREAM_TYPE_PIPE; } DestroyString(Tempstr); return(S); }
STREAM *STREAMOpenFile(const char *FilePath, int Flags) { int fd, Mode=FALSE; STREAM *Stream; struct stat myStat; Mode = Flags & ~(O_LOCK|O_TRUNC); if (strcmp(FilePath,"-")==0) { Stream=STREAMFromDualFD(0,1); Stream->Path=CopyStr(Stream->Path,FilePath); return(Stream); } fd=open(FilePath, Mode, 0600); if (fd==-1) return(NULL); if (Flags & O_LOCK) { if (flock(fd,LOCK_EX | LOCK_NB)==-1) { close(fd); return(NULL); } } // check for symlink naughtyness. Basically a malicious user can // try to guess the name of the file we are going to open in order // to get us to write somewhere other than intended. if (lstat(FilePath, &myStat) !=0) { close(fd); return(NULL); } if (S_ISLNK(myStat.st_mode)) { syslog(LOG_USER | LOG_WARNING, "STREAMOpenFile Opened symlink when trying to open %s. Possible DOS attack?",FilePath); close(fd); return(NULL); } if (Flags & O_TRUNC) ftruncate(fd,0); Stream=STREAMFromFD(fd); Stream->Path=CopyStr(Stream->Path,FilePath); STREAMSetTimeout(Stream,0); STREAMSetFlushType(Stream,FLUSH_FULL,0); return(Stream); }
STREAM *STREAMSpawnFunction(BASIC_FUNC Func, void *Data) { int to_fd, from_fd; pid_t pid; STREAM *S=NULL; char *Tempstr=NULL; pid=PipeSpawnFunction(&to_fd, &from_fd, COMMS_COMBINE_STDERR, Func, Data, "", "" ); if (pid > 0) S=STREAMFromDualFD(from_fd, to_fd); if (S) { STREAMSetFlushType(S,FLUSH_LINE,0,0); Tempstr=FormatStr(Tempstr,"%d",pid); STREAMSetValue(S,"PeerPID",Tempstr); } DestroyString(Tempstr); return(S); }
STREAM *STREAMSpawnCommand(const char *Command, const char *User, const char *Group, int Flags) { int to_fd, from_fd; pid_t pid; STREAM *S=NULL; char *Tempstr=NULL; if (Flags & SPAWN_TRUST_COMMAND) Tempstr=CopyStr(Tempstr,Command); else Tempstr=MakeShellSafeString(Tempstr, Command, 0); if (Flags & COMMS_BY_PTY) { pid=PseudoTTYSpawn(&to_fd,Tempstr,User,Group,Flags); if (pid > 0) S=STREAMFromFD(to_fd); } else { if (Flags & COMMS_COMBINE_STDERR) { pid=PipeSpawn(&to_fd, &from_fd, COMMS_COMBINE_STDERR, Tempstr,User,Group); } else pid=PipeSpawn(&to_fd, &from_fd, NULL, Tempstr,User,Group); if (pid > 0) S=STREAMFromDualFD(from_fd, to_fd); } if (S) { STREAMSetFlushType(S,FLUSH_LINE,0,0); Tempstr=FormatStr(Tempstr,"%d",pid); STREAMSetValue(S,"PeerPID",Tempstr); } DestroyString(Tempstr); return(S); }
int STREAMConnectToHost(STREAM *S, char *DesiredHost, int DesiredPort,int Flags) { ListNode *Curr; char *Token=NULL, *ptr; int result=FALSE; int HopNo=0, val; ListNode *LastHop=NULL; S->Path=FormatStr(S->Path,"tcp:%s:%d",DesiredHost,DesiredPort); //Find the last hop, used to decide what ssh command to use Curr=ListGetNext(S->Values); while (Curr) { ptr=GetToken(Curr->Tag,":",&Token,0); if (strcasecmp(Token,"ConnectHop")==0) LastHop=Curr; Curr=ListGetNext(Curr); } STREAMSetFlushType(S,FLUSH_LINE,0); Curr=ListGetNext(S->Values); while (Curr) { ptr=GetToken(Curr->Tag,":",&Token,0); if (strcasecmp(Token,"ConnectHop")==0) result=STREAMProcessConnectHop(S, (char *) Curr->Item,Curr==LastHop); HopNo++; if (! result) break; Curr=ListGetNext(Curr); } //If we're not handling the connection through 'Connect hops' then //just connect to host if ((HopNo==0) && StrLen(DesiredHost)) { if (Flags & CONNECT_NONBLOCK) S->Flags |= SF_NONBLOCK; val=Flags; if (S->Timeout > 0) val |= CONNECT_NONBLOCK; S->in_fd=ConnectToHost(DesiredHost,DesiredPort,val); S->out_fd=S->in_fd; if (S->in_fd > -1) result=TRUE; } if (result==TRUE) { if (Flags & CONNECT_NONBLOCK) { S->State |=SS_CONNECTING; S->Flags |=SF_NONBLOCK; } else { S->State |=SS_CONNECTED; STREAMDoPostConnect(S, Flags); } } return(result); }
int STREAMProcessConnectHop(STREAM *S, char *HopURL, int LastHop) { int val, result=FALSE; char *Token=NULL, *Token2=NULL; char *Tempstr=NULL; char *User=NULL, *Host=NULL,*Pass=NULL, *KeyFile=NULL; int Port=0; ParseConnectDetails(HopURL, &Token, &Host, &Token2, &User, &Pass, NULL); Port=atoi(Token2); val=MatchTokenFromList(Token,HopTypes,0); switch (val) { case CONNECT_HOP_TCP: if (S->in_fd==-1) { S->in_fd=ConnectToHost(Host,Port,0); S->out_fd=S->in_fd; if (S->in_fd > -1) result=TRUE; } break; case CONNECT_HOP_HTTPTUNNEL: result=DoHTTPProxyTunnel(S, Host, Port, S->Path, 0); break; case CONNECT_HOP_SSH: case CONNECT_HOP_SSHTUNNEL: result=ConnectHopSSH(S, val, Host, Port, User, Pass, S->Path); break; case CONNECT_HOP_SOCKS4: result=ConnectHopSocks(S, val, Host, Port, User, Pass, S->Path); break; case CONNECT_HOP_SHELL_CMD: break; case CONNECT_HOP_TELNET: if (Port > 0) { Tempstr=FormatStr(Tempstr,"telnet -8 %s %d ",Host, Port); } else Tempstr=FormatStr(Tempstr,"telnet -8 %s ",Host); if (S->in_fd==-1) { PseudoTTYSpawn(& S->in_fd,Tempstr,0); S->out_fd=S->in_fd; if (S->in_fd > -1) { result=TRUE; STREAMSetFlushType(S,FLUSH_LINE,0,0); } } else { Tempstr=CatStr(Tempstr,";exit\n"); STREAMWriteLine(Tempstr,S); result=TRUE; } if (StrLen(User) > 0) { Tempstr=MCopyStr(Tempstr,User,"\n",NULL); STREAMExpectAndReply(S,"ogin:",Tempstr); } if (StrLen(Pass) > 0) { Tempstr=MCopyStr(Tempstr,Pass,"\n",NULL); STREAMExpectAndReply(S,"assword:",Tempstr); } STREAMExpectSilence(S,2); break; } DestroyString(Tempstr); DestroyString(Token); DestroyString(KeyFile); DestroyString(Host); DestroyString(User); DestroyString(Pass); STREAMFlush(S); return(result); }
int ConnectHopSSH(STREAM *S,int Type, char *Host, int Port, char *User, char *Pass, char *NextHop) { char *Tempstr=NULL, *KeyFile=NULL, *Token=NULL, *Token2=NULL; STREAM *AuthS; int result=FALSE, val; unsigned int TunnelPort=0; if (Type==CONNECT_HOP_SSHTUNNEL) { TunnelPort=(rand() % (0xFFFF - 9000)) +9000; //Host will be Token, and port Token2 ParseConnectDetails(NextHop, NULL, &Token, &Token2, NULL, NULL, NULL); Tempstr=FormatStr(Tempstr,"ssh -2 -N %s@%s -L %d:%s:%s ",User,Host,TunnelPort,Token,Token2); } else Tempstr=MCopyStr(Tempstr,"ssh -2 -T ",User,"@",Host, " ", NULL ); if (strncmp(Pass,"keyfile:",8)==0) { if (S->in_fd != -1) { Token=FormatStr(Token,".%d-%d",getpid(),time(NULL)); SendPublicKeyToRemote(S,Token,Pass+8); KeyFile=CopyStr(KeyFile,Token); } Tempstr=MCatStr(Tempstr,"-i ",KeyFile," ",NULL); } if (Port > 0) { Token=FormatStr(Token," -p %d ",Port); Tempstr=CatStr(Tempstr,Token); } if (Type==CONNECT_HOP_SSHTUNNEL) { Tempstr=CatStr(Tempstr, " 2> /dev/null"); AuthS=STREAMSpawnCommand(Tempstr,COMMS_BY_PTY); STREAMSetValue(S,"HelperPID:SSH",STREAMGetValue(AuthS,"PeerPID")); } else if (S->in_fd==-1) { Tempstr=CatStr(Tempstr, " 2> /dev/null"); PseudoTTYSpawn(&S->in_fd,Tempstr,0); S->out_fd=S->in_fd; if (S->in_fd > -1) { result=TRUE; STREAMSetFlushType(S,FLUSH_LINE,0,0); } AuthS=S; } else { if (StrLen(KeyFile)) Tempstr=MCatStr(Tempstr," ; rm -f ",KeyFile,NULL); Tempstr=CatStr(Tempstr,"; exit\n"); STREAMWriteLine(Tempstr,S); result=TRUE; AuthS=S; } if ((StrLen(KeyFile)==0) && (StrLen(Pass) > 0)) { Token=MCopyStr(Token,Pass,"\n",NULL); for (val=0; val < 3; val++) { if (STREAMExpectAndReply(AuthS,"assword:",Token)) break; } } STREAMSetTimeout(AuthS,100); //STREAMExpectSilence(AuthS); sleep(3); if (Type==CONNECT_HOP_SSHTUNNEL) { S->in_fd=ConnectToHost("127.0.0.1",TunnelPort,0); S->out_fd=S->in_fd; if (S->in_fd > -1) result=TRUE; } DestroyString(Tempstr); DestroyString(KeyFile); DestroyString(Token2); DestroyString(Token); return(result); }
void ConnectManagerMainLoop() { TConnectManagerItem *Item, *NewItem; ListNode *Curr, *Prev; int highfd=0; fd_set ReadSet, WriteSet; int sock, result, SelectResult, NextTimerFire; STREAM *S; time_t Now; struct timeval tv; int MoreData=FALSE; while (1) { MoreData=FALSE; time(&Now); NextTimerFire=60; Curr=ListGetNext(Timers); while (Curr) { Item=(TConnectManagerItem *) Curr->Item; if (Item->LastTimerFire==0) Item->LastTimerFire=Now; result=(Item->LastTimerFire + Item->TimerVal) - Now; if (result < NextTimerFire) NextTimerFire=result; Curr=ListGetNext(Curr); } FD_ZERO(&ReadSet); FD_ZERO(&WriteSet); Curr=ListGetNext(ConnectManServers); while (Curr) { Item=(TConnectManagerItem *) Curr->Item; S=(STREAM *) Item->Data; FD_SET(S->in_fd,&ReadSet); if (S->in_fd > highfd) highfd=S->in_fd; Curr=ListGetNext(Curr); } Curr=ListGetNext(ConnectManClients); while (Curr) { Item=(TConnectManagerItem *) Curr->Item; S=(STREAM *) Item->Data; if (! S) { ListDeleteNode(Curr); continue; } if (S->State & SS_CONNECTING) { FD_SET(S->in_fd,&WriteSet); } if (S->InEnd > S->InStart) MoreData=TRUE; else { //always add to read set FD_SET(S->in_fd,&ReadSet); if (S->in_fd > highfd) highfd=S->in_fd; } Curr=ListGetNext(Curr); } if (MoreData) { tv.tv_usec = 10; tv.tv_sec = 0; SelectResult=0; } else { //SELECT!!! tv.tv_usec = 20000; tv.tv_sec = NextTimerFire; } SelectResult=select(highfd+1,&ReadSet,&WriteSet,NULL,&tv); if (SelectResult > 0) { Curr=ListGetNext(ConnectManServers); while (Curr) { Item=(TConnectManagerItem *) Curr->Item; S=(STREAM *) Item->Data; if (! S) { ListDeleteNode(Curr); continue; } if (FD_ISSET(S->in_fd,&ReadSet)) { sock=TCPServerSockAccept(S->in_fd,&S->Path); if (sock > -1) { S=STREAMFromFD(sock); STREAMSetFlushType(S,FLUSH_LINE,0,0); NewItem=ConnectManagerAddIncoming(S,Item->Name, Item->OnData); if (Item->OnConnect) Item->OnConnect(NewItem); } } Curr=ListGetNext(Curr); } } Curr=ListGetNext(ConnectManClients); while (Curr) { Item=(TConnectManagerItem *) Curr->Item; S=(STREAM *) Item->Data; if (! S) { ListDeleteNode(Curr); continue; } if ((SelectResult > 0) && FD_ISSET(S->in_fd,&WriteSet)) { if (S->State & SS_CONNECTING) { if (STREAMIsConnected(S)) { STREAMSetFlags(S, 0, SF_NONBLOCK); if (Item->OnConnect) Item->OnConnect(Item); } } } if ( (S->InEnd > S->InStart) || ((SelectResult > 0) && (FD_ISSET(S->in_fd,&ReadSet))) ) { if (! (S->State & SS_CONNECTING)) { if (Item->OnData) { result=Item->OnData(S, Item->Name); if (! result) { STREAMClose(S); Prev=ListGetPrev(Curr); ListDeleteNode(Curr); free(Item); Curr=Prev; } else if (result==RECONNECT) { STREAMClose(S); S=STREAMCreate(); STREAMConnectToHost(S,Item->Host,Item->Port,CONNECT_NONBLOCK); Item->Data=(void *) S; } } } } Curr=ListGetNext(Curr); } time(&Now); Curr=ListGetNext(Timers); while (Curr) { Item=(TConnectManagerItem *) Curr->Item; if ( (Now - Item->LastTimerFire) >= Item->TimerVal ) { if (Item->OnData) ((ONTIMER_FUNC)Item->OnData)(Item->Data,Item->Name); Item->LastTimerFire=Now; } Curr=ListGetNext(Curr); } } }