char *FindFileInPath(char *InBuff, const char *File, const char *Path) { char *Tempstr=NULL, *CurrPath=NULL, *RetStr=NULL, *ptr; RetStr=CopyStr(InBuff,""); if (*File=='/') { CurrPath=CopyStr(CurrPath,""); ptr=""; //so we execute once below } else ptr=GetToken(Path,":",&CurrPath,0); while (ptr) { CurrPath=SlashTerminateDirectoryPath(CurrPath); Tempstr=MCopyStr(Tempstr,CurrPath,File,NULL); if (access(Tempstr,F_OK)==0) { RetStr=CopyStr(RetStr,Tempstr); break; } ptr=GetToken(ptr,":",&CurrPath,0); } DestroyString(Tempstr); DestroyString(CurrPath); return(RetStr); }
char *FindFileInPath(char *InBuff, char *File, char *Path) { char *Tempstr=NULL, *CurrPath=NULL, *RetStr=NULL, *ptr; RetStr=CopyStr(InBuff,""); ptr=Gettoken(Path,":",&CurrPath,0); while (ptr) { CurrPath=SlashTerminateDirectoryPath(CurrPath); Tempstr=MCopyStr(Tempstr,CurrPath,File,NULL); if (access(Tempstr,F_OK)==0) { RetStr=CopyStr(RetStr,Tempstr); break; } ptr=Gettoken(ptr,":",&CurrPath,0); } DestroyString(Tempstr); DestroyString(CurrPath); return(RetStr); }
int FindFilesInPath(const char *File, const char *Path, ListNode *Files) { char *Tempstr=NULL, *CurrPath=NULL, *ptr; int i; glob_t Glob; if (*File=='/') { CurrPath=CopyStr(CurrPath,""); ptr=""; //so we execute once below } else ptr=GetToken(Path,":",&CurrPath,0); while (ptr) { CurrPath=SlashTerminateDirectoryPath(CurrPath); Tempstr=MCopyStr(Tempstr,CurrPath,File,NULL); glob(Tempstr,0,0,&Glob); for (i=0; i < Glob.gl_pathc; i++) ListAddItem(Files,CopyStr(NULL,Glob.gl_pathv[i])); globfree(&Glob); ptr=GetToken(ptr,":",&CurrPath,0); } DestroyString(Tempstr); DestroyString(CurrPath); return(ListSize(Files)); }
char *ParentDirectory(char *RetBuff, const char *Path) { char *RetStr=NULL, *ptr; int len; RetStr=CopyStr(RetBuff,Path); len=StrLen(RetStr); //Don't strip slash if directory is root dir if (len > 1) { StripDirectorySlash(RetStr); //Now strip off one dir name (the result of '..') ptr=strrchr(RetStr,'/'); if (ptr) *ptr='\0'; if (StrLen(RetStr)==0) RetStr=CopyStr(RetStr,"/"); } RetStr=SlashTerminateDirectoryPath(RetStr); return(RetStr); }
void DoBindMounts(char *DirList, int Flags) { char *MntSrc=NULL, *MntDest=NULL, *ptr, *dptr; ptr=GetToken(DirList,",",&MntSrc,0); while (ptr) { //if there's a ':' character in the mount definition, then it means that //we're mounting a directory in a different place than it would normally exist. //the default is to mount, say, /usr/lib as /usr/lib in the chroot. But if we //are passed /home/mylibs:/lib then we mount /home/mylibs as /lib in the chroot dptr=strrchr(MntSrc,':'); if (dptr) { *dptr='\0'; dptr++; } else dptr=MntSrc; while (*dptr == '/') dptr++; MntDest=CopyStr(MntDest,dptr); MntDest=SlashTerminateDirectoryPath(MntDest); MakeDirPath(MntDest,0555); //Try a remount first. This prevents us mounting over and over //on the same mount point if (mount(MntSrc,MntDest,"",MS_BIND | MS_REMOUNT,"") !=0) { mount(MntSrc,MntDest,"",MS_BIND,""); } ptr=GetToken(ptr,",",&MntSrc,0); } DestroyString(MntSrc); DestroyString(MntDest); }
int HTTPServerSendDirectory(STREAM *S, HTTPSession *Session, char *Path, ListNode *Vars) { int DirSent=FALSE; char *Tempstr=NULL, *Token=NULL, *ptr; int Flags=0, Format, max=0; TPathItem **Files; int result=FALSE; //Maybe we can get out of sending the directory. Check 'IfModifiedSince' if ((Session->IfModifiedSince > 0) && (Session->LastModified > 0) && (Session->LastModified <= Session->IfModifiedSince)) { // HTTPServerSendHTML(S, Session, "304 Not Modified",""); // return; } //Get Time for uses like showing 'recent files' time(&Now); if (HTTPServerDecideToCompress(Session,NULL)) Session->Flags |= SESSION_ENCODE_GZIP; if (Settings.DirListFlags & DIR_INDEX_FILES) { DirSent=DirectoryTryIndex(S, Session, Path); } if (! DirSent) { Format=RequestedListingType(Session,&Flags); switch (Format) { case ACTION_HTML: case ACTION_M3U: case ACTION_CSV: max+=LoadDir(Path, Session, Flags, &Files); switch (Format) { case ACTION_M3U: HTTPServerSendM3U(S,Session,Path,max,Files); break; case ACTION_CSV: HTTPServerSendCSV(S,Session,Path,max,Files); break; case ACTION_HTML: HTTPServerSendDirList(S,Session,Path,Flags,max,Files); break; } break; //TAR doesn't send a list of files, it sends the actual files, so it doesn't need to use //LoadDir in order to handle VPaths etc. case ACTION_PACK: result=HTTPServerSendPackedDir(S,Session,Path); break; case ACTION_UPLOAD: UploadSelectPage(S,Session,Path); break; case ACTION_EDIT: DirectoryItemEdit(S,Session,Path,0); break; case ACTION_EDIT_ACCESSTOKEN: DirectoryItemEdit(S,Session,Path, FDETAILS_ACCESSTOKEN); break; case ACTION_MKDIR: Token=SessionGetArgument(Token, Session, "mkdir"); Tempstr=CopyStr(Tempstr,Path); Tempstr=SlashTerminateDirectoryPath(Tempstr); Tempstr=CatStr(Tempstr,Token); LogToFile(Settings.LogPath,"MKDIR: [%s] [%s] [%s]\n",Path,Token,Tempstr); mkdir(Tempstr, 0770); HTTPServerSendResponse(S, Session, "302", "", Session->URL); break; case ACTION_DELETE: DirectoryDeleteItem(S, Session, Path); HTTPServerSendToParentDir(S, Session); break; case ACTION_DELETE_SELECTED: DirectoryDeleteSelected(S, Session, Path); HTTPServerSendResponse(S, Session, "302", "", Session->URL); break; case ACTION_RENAME: Token=SessionGetArgument(Token, Session, "renameto"); Tempstr=CopyStr(Tempstr,Path); ptr=strrchr(Tempstr,'/'); if (ptr) *ptr='\0'; Tempstr=SlashTerminateDirectoryPath(Tempstr); Tempstr=CatStr(Tempstr,Token); if (rename(Path,Tempstr) !=0) { LogToFile(Settings.LogPath,"ERROR: Failed to rename: [%s] to [%s]. Error was: %s",Path,Tempstr,strerror(errno)); } else LogToFile(Settings.LogPath,"Renamed Item: [%s] to [%s]",Path,Tempstr); HTTPServerSendToParentDir(S, Session); break; case ACTION_SAVEPROPS: LogToFile(Settings.LogPath,"SAVEPROPS: [%s]\n",Path); FileDetailsSaveProps(S, Session, Path); Tempstr=MCopyStr(Tempstr,Session->URL,"?format=edit",NULL); HTTPServerSendResponse(S, Session, "302", "", Tempstr); break; default: HTTPServerSendHTML(S, Session, "403 Index Listing Forbidden","This server is not configured to list directories."); break; } } DestroyString(Tempstr); DestroyString(Token); return(result); }
//yes, '***', three levels of pointer! It's an array of pointers that //has to be passed into the function as a pointer int LoadDir(char *Path, HTTPSession *Session, int Flags, TPathItem ***fl_ptr) { char *Tempstr=NULL, *URL=NULL, *Dir=NULL; glob_t Glob; struct stat Stat; TPathItem *File, **Files; ListNode *Curr; int i, val, fcount=0; Tempstr=MCopyStr(Tempstr,Path,"/*",NULL); glob(Tempstr,0,0,&Glob); Dir=CopyStr(Dir,Session->URL); Dir=SlashTerminateDirectoryPath(Dir); //Allocate As Many Items As glob found, plus VPaths, plus one for '..' val=Glob.gl_pathc+1; if (Settings.DirListFlags & DIR_SHOW_VPATHS) val+=ListSize(Settings.VPaths); *fl_ptr=(TPathItem **) calloc(val , sizeof(TPathItem *)); Files=*fl_ptr; //if we are at '/' then don't offer a parent directory if (StrLen(Path) > 1) { Tempstr=ParentDirectory(Tempstr, Session->URL); URL=FormatURL(URL,Session,Tempstr); Files[0]=PathItemCreate(PATHTYPE_DIR,Tempstr,".."); fcount++; } //LoadVPaths if in top-level dir if (Settings.DirListFlags & DIR_SHOW_VPATHS) { if (strcmp(Path,Session->StartDir)==0) { Curr=ListGetNext(Settings.VPaths); while (Curr) { File=(TPathItem *) Curr->Item; if ((File->Type==PATHTYPE_EXTFILE) && (strcmp(File->URL,"/") !=0)) { Files[fcount]=PathItemCreate(PATHTYPE_DIR,File->URL,File->URL); fcount++; } Curr=ListGetNext(Curr); } } } for (i=0; i < Glob.gl_pathc; i++) { Tempstr=MCopyStr(Tempstr,Dir,GetBasename(Glob.gl_pathv[i]),NULL); URL=FormatURL(URL,Session,Tempstr); if (stat(Glob.gl_pathv[i],&Stat) > -1) { if (S_ISDIR(Stat.st_mode)) File=PathItemCreate(PATHTYPE_DIR,URL,Glob.gl_pathv[i]); else File=PathItemCreate(PATHTYPE_FILE,URL,Glob.gl_pathv[i]); File->Mtime=Stat.st_mtime; File->Size=Stat.st_size; } Files[fcount]=File; fcount++; } switch (Flags & SORT_TYPE_MASK) { case SORT_SIZE: qsort(Files,fcount,sizeof(TPathItem *),FilesSortSizeCmp); break; case SORT_RSIZE: qsort(Files,fcount,sizeof(TPathItem *),FilesRSortSizeCmp); break; case SORT_TIME: qsort(Files,fcount,sizeof(TPathItem *),FilesSortTimeCmp); break; case SORT_RTIME: qsort(Files,fcount,sizeof(TPathItem *),FilesRSortTimeCmp); break; case SORT_NAME: qsort(Files,fcount,sizeof(TPathItem *),FilesSortNameCmp); break; case SORT_RNAME: qsort(Files,fcount,sizeof(TPathItem *),FilesRSortNameCmp); break; } globfree(&Glob); DestroyString(Dir); DestroyString(URL); DestroyString(Tempstr); //i will equal 'Glob.pathc' at end of loop, we also added '..' so return i+1 return(fcount); }
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 HTTPServerSetUserContext(HTTPSession *Session) { char *ChrootDir=NULL, *Tempstr=NULL; Session->StartDir=CopyStr(Session->StartDir,Settings.DefaultDir); ChrootDir=CopyStr(ChrootDir,Settings.DefaultDir); LogToFile(Settings.LogPath,"SETCTX: %d %s home=%s",Session->MethodID,ChrootDir,Session->HomeDir); if (IsProxyMethod(Session->MethodID)) { //Do not chroot for proxy commands } else { if (Settings.Flags & FLAG_CHHOME) ChrootDir=CopyStr(ChrootDir,Session->HomeDir); //if (Settings.Flags & FLAG_LOG_VERBOSE) LogToFile(Settings.LogPath,"ChRoot to: %s home=%s",ChrootDir,Session->HomeDir); if (chdir(ChrootDir) !=0) { LogToFile(Settings.LogPath,"ERROR: CHDIR FAILED: %d %s %s",getuid(),ChrootDir,strerror(errno)); HTTPServerSendHTML(Session->S, Session, "500 Internal Server Error","Problem switching to home-directory"); LogFileFlushAll(TRUE); _exit(1); } chroot("."); Session->StartDir=CopyStr(Session->StartDir,"/"); } /* /Not working yet else if (Settings.Flags & FLAG_CHSHARE) { chdir(Settings.DefaultDir); chroot("."); if (strncmp(Session->StartDir,Settings.DefaultDir,StrLen(Settings.DefaultDir))==0) { Tempstr=MCopyStr(Tempstr,"/",Session->StartDir+StrLen(Settings.DefaultDir),NULL); chdir(Tempstr); Session->StartDir=CopyStr(Session->StartDir,Tempstr); } } */ Session->StartDir=SlashTerminateDirectoryPath(Session->StartDir); LogToFile(Settings.LogPath,"User Context: Chroot: %s, StartDir: %s, HomeDir: %s, UserID: %d, GroupID: %d,",ChrootDir, Session->StartDir, Session->HomeDir, Session->RealUserUID,Session->GroupID); if (Session->GroupID > 0) { if (setgid(Session->GroupID) != 0) { HTTPServerSendHTML(Session->S, Session, "500 Internal Server Error","Problem switching to configured user-group"); LogToFile(Settings.LogPath,"ERROR: Failed to switch group to %s/%d. Exiting",Session->RealUser,Session->RealUserUID); _exit(1); } } else if (Settings.DefaultGroupID > 0) { if (setgid(Settings.DefaultGroupID) != 0) { HTTPServerSendHTML(Session->S, Session, "500 Internal Server Error","Problem switching to configured user-group"); LogToFile(Settings.LogPath,"ERROR: Failed to switch group to %s/%d. Exiting",Session->RealUser,Session->RealUserUID); _exit(1); } } DropCapabilities(CAPS_LEVEL_CHROOTED); if (setresuid(Session->RealUserUID,Session->RealUserUID,Session->RealUserUID)!=0) { HTTPServerSendHTML(Session->S, Session, "500 Internal Server Error","Problem switching to configured user"); LogToFile(Settings.LogPath,"ERROR: Failed to switch user to %s/%d. Exiting",Session->RealUser,Session->RealUserUID); _exit(1); } //drop everything! (In case someting went wrong with setresuid) DropCapabilities(CAPS_LEVEL_SESSION); DestroyString(Tempstr); DestroyString(ChrootDir); return(TRUE); }