/* ftp.c */ #define FTPMASTER /* * Includes */ #include #include #include "vftp.h" #include "dfault.h" #include "evtdef.h" #include "hstdef.h" #include "prodef.h" #include "ftppi.h" #include "cliutl.h" #include "tsxutl.h" #include "kbdutl.h" #include "usrblk.h" #include "inicli.h" #include "cticks.h" #include "suspnd.h" /* * Internal routines */ extern int ftpgets(); /* (str,lim,echo) read line from keyboard */ extern VOID ftpexit(); /* (i) exit from ftp */ extern int dumpcon(); /* dump connection to screen */ extern VOID filter(); /* (cnt) filter telnet options */ extern int question(); /* (cstr,clen,qstr) pose a question */ extern int ftpresp(); /* (s,len) response function for tsxutl */ extern VOID lcd(); /* (s) change local directory */ extern VOID ldelete(); /* (s) delete a local file */ extern VOID ldelfil(); /* (s) subroutine of ldelete */ extern VOID lls(); /* (s) list local directory */ extern VOID lmkdir(); /* (s) make a local directory */ extern VOID lprotect(); /* (s) set protection flag on local file */ extern VOID setfilp(); /* (s) subroutine of lprotect */ extern VOID lunprotect(); /* (s) clr protection flag on a local file */ extern VOID clrfilp(); /* (s) subroutine of lunprotect */ extern VOID lsterr(); /* print error string from tsxutl */ extern int toggle(); /* (cstr,wstr,flag,on,off) toggle flags */ extern VOID ftppi(); /* (command) protocol interpreter */ extern int setmode(); /* (mode,filnam) set mode, return old mode */ extern int ftpopen(); /* (lpnum,dst,port) open FTP connection */ extern int ftpport(); /* set up listening port */ extern int ftpdo(); /* (s,filnam) do a command */ extern int ftpreplies(); /* (rcode) get response to server */ extern int ftpabort(); /* (how) abort FTP */ extern int rgetline(); /* get line from remote server */ extern VOID userftpd(); /* FTP recieve and send file functions */ extern int getword(); /* (s,word) remove word from string */ extern int checkoredir(); /* (cmnd,filnam) check redirected output */ extern int finduniq(); /* (nam,lst,lstsz) find unique string */ extern int checkevent(); /* process server events */ extern int getnname(); /* (s,word) get next name from list */ extern VOID strlwr(); /* (s) convert string to lower case */ extern char *stptok(); /* (p,word,ilen,delim) stop on token */ extern char *stpblk(); /* (s) skip spaces and tabs */ extern int chkusr(); /* check username / password */ extern int Scompass(); /* (ps,en) compare passwords */ extern VOID printtxt(); /* (s) printout text */ /* * Debugging options * * bit 0 (0x01) enable event printing * bit 1 (0x02) enable command printing * bit 2 (0x04) debug ftpdo() * bit 3 (0x08) debug ftpport() * bit 4 (0x10) debug ftpreplies() * bit 5 (0x20) debug rgetline() * bit 6 (0x40) debug userftpd() * bit 7 (0x80) debug getword() * bit 8 (0x100) debug getnname() */ #define DBUGTRUE -1 static char *usetxt[] = { "", #ifdef DEBUGOPTION " FTP [?] [-d level]", " [-f filename] [-p filename] [-ghinrv] [destination host]", " ? List this Help Text and Exit FTP", " d level Debug Level" " 1 - enable event printing", " 2 - enable command printing", " 4 - enable ftpdo() printing", " 8 - enable ftpport() printing", " 16 - enable ftpreplies printing", " 32 - enable rgetline() printing", " 64 - enable userftpd() printing", " 128 - enable getword() printing", " 256 - enable getnname() printing", #else " FTP [?] [-f filename] [-p filename] [-ginrv] [destination host]", " ? List this Help Text and Exit FTP", #endif " f filename Command File", " g Wildcard Expansion Disabled", " h FTP Help List", " i Interactive Prompting Off", " n AutoLogin Disabled on Connect", " p filename Specify the Password Filespec", " r Output Redirection Disabled", " v Verbose Mode Disabled", "", 0 }; #define FASCII 0 #define FIMAGE 1 #define FALSE 0 #define TRUE 1 #define SUCCESS 2 #define HAVEDATA 4 #define ERROR -1 #define NONE -2 #define ABORT -3 #define INCOMPLETE -4 #define AMBIGUOUS -5 static char /* password file */ *pass = "sy:paswrd.fil"; static int pswdreqd = 1, /* password required */ xp = 0, /* general pointer */ towrite = 0, /* file transfer pointer */ len = 0, /* file transfer length */ ftpcskt = -1, /* current command port */ ftpdskt = -1, /* current data port */ ftpstate = 0, /* state for background process */ ftpfilemode = 0, /* file open mode for transfer */ finished = TRUE, /* file transfer complete flag */ hash = 0, /* hash mark printing */ hashnum = 0, /* number of hash marks printed */ hashcnt = 0, /* hash mark counter */ linked = 0, /* not connected */ sendport = 1, /* to send ports or not */ verbose = 1, /* informative messages */ redirect = 1, /* check for ouput redirection */ bell = 0, /* sound bell */ autologin = 1, /* login on connect */ capture = 0, /* capture data or not */ stopcapture = FALSE, /* stop capture of data */ prompt = 1, /* check on multiple commands */ fromtty = TRUE, /* default input from tty */ fildev = 1, /* file oriented devices */ wild = 1; /* expand wildcards */ static long start, /* transfer start time */ tbytes; /* number of bytes transferred */ static FILE *fromfp = NULL; /* file pointer for input command file */ static FILE *ftpfh = NULL; /* file pointer for ftp transfers */ #define BUFFERS 2048 /* size of buffer */ #define READSIZE 512 /* how much to read */ #define GBUFSIZE 200 /* general buffer size */ static char destname[50]={0,0}; /* who to connect to */ static char ftpcommand[GBUFSIZE]; /* command to execute */ static char printline[GBUFSIZE]; /* line to display */ static char s[GBUFSIZE]; /* line from other side */ static char captlist[BUFFERS]; /* response string */ char xs[BUFFERS]; /* buffer space for file transfer */ /* * main - main procedure. Displays opening message, parses arguments, * initializes network, reads user commands and executes them, and * cleans up. */ static char fromfile[20] = ""; main(argc,argv) int argc; char *argv[]; { int i,j,k,c; /* * Initialize for TSX+ clients */ inicli(); /* * Initialize kb handler * Set the break character to ^C */ kb_init(0x03); /* * identify self */ printtxt(vrstxt); /* * initialize destination host name */ destname[0] = '\0'; /* * parse arguments */ for(i=1; i "); /* * read cmd from user */ ftpgets(ftpcommand,200,1); } } /* * General looping question routine * loops until a response is given * returns 1 on ABORT * else 0 */ static int question(cstr,clen,qstr) char *cstr,*qstr; int clen; { while(!(*(stpblk(cstr)))) { /* * get arg from user */ kb_puts(qstr); if(rtresp(cstr,clen)) return(1); } return(0); } /* * Routine to get a keyboard response * returns 1 on ABORT * else 0 */ int rtresp(st,ln) char *st; int ln; { return((ftpgets(st,ln,1)==ABORT) ? 1 : 0); } /* * tstbrk * * if fndbrk is set then: * (1) terminate command file mode * (2) return(1) * else * return(0) */ int tstbrk() { if(fndbrk) { if(fromfp != NULL) { fclose(fromfp); fromfp = NULL; fromtty = TRUE; kb_puts("\r\nCommand File Input Aborted\r\n"); } fndbrk = 0; return(1); } else { return(0); } } /* * ftpgets * * read a line from the keyboard * returns ABORT if keyboard input aborted * or non-zero on success */ int ftpgets(str,lim,echo) register char *str; /* where to put the line */ int lim,echo; /* max chars to read, echo? */ { register char *save; int c; save = str; /* beginning of line */ *save = '\0'; if(tstbrk()) { kb_puts("^C\r\n"); return(ABORT); } if(!fromtty) { if(fromfp != NULL) { if(fgetss(str,lim,fromfp) != NULL) { if(echo) { kb_puts(str); kb_nline(); } } else { fclose(fromfp); fromfp = NULL; fromtty = TRUE; kb_puts("[EOF]\r\n"); } return(strlen(str)); } else { fromtty = TRUE; } } while(1) { /* * build string from keyboard */ c = kb_gets(str,lim,echo); if(1 <= c && c <= 31) { kb_nline(); return(strlen(save)); } /* * check for abort */ if(tstbrk()) { *save = '\0'; kb_puts("^C\r\n"); return(ABORT); } /* * check event queue */ checkevent(); suspnd(0); } } /* * ftpexit * * exit from ftp */ static VOID ftpexit(i) int i; { if(i == ABORT) { kb_puts("\r\nFTP session aborted by TCPIP\r\n"); } else { while(linked && (checkevent() != ABORT)) { suspnd(0); } } /* * close connections */ skclose(ftpcskt); skrelease(ftpcskt,1); skclose(ftpdskt); skrelease(ftpdskt,1); rtclose(ftpfh); suspnd(0); errhandle(); /* * Reset subdirectory specifications */ cd("dk:"); kb_puts("\r\nEscaping from FTP\r\n"); exit(0); } /* * dumpcon * * take everything from a connection and send it to the screen * return -1 on closed connection, else 0, 1 if paused */ static int dumpcon() { int cnt; /* * get some from queue */ do { cnt = skread(ftpcskt,s,GBUFSIZE); if(cnt>0) { skdeque(ftpcskt); /* * display on screen, etc. */ filter(cnt); } } while(cnt>0); /* * 0 normally, -1 if connection closed */ return(cnt); } /* * filter * * filter telnet options on incoming data */ static VOID filter(cnt) int cnt; { int i; #ifdef DEBUGOPTION if(debug&0x100) { kbprintf("filter(): cnt=%d \r\n",cnt); } #endif /* * put on screen */ for(i=0; i=1 && n<=NCMDS+1) { if((fcmdfp = fopen("sy:ftpcmd.txt","r")) != NULL) { for(i=0; fgetss(txt,80,fcmdfp)!=NULL && i0) { debug = i; kbprintf("Debugging on(debug=%d).\r\n",debug); } else { toggle(command,word,&debug, "Debugging on.\r\n", "Debugging off.\r\n"); } return; #else case DEBUG: /* no debugging */ kb_puts("Debugging not available.\r\n"); return; #endif case WILD: /* wildcard expansion */ return( toggle(command,word,&wild, "Wildcards enabled.\r\n", "Wildcards disabled.\r\n") ); case HASH: /* hash mark printing */ return( toggle(command,word,&hash, "Hash printing on(1024 bytes/hash mark).\r\n", "Hash printing off.\r\n") ); case HOME: /* go to home directory */ kbprintf("Home directory is dk: --> %s\r\n", gethome(line)); cd("dk:"); lsterr(); return; case INTERACTIVE: /* turn on interactive prompting */ case NONINTERACTIVE: /* turn off interactive prompting */ case PROMPT: /* interactive prompting */ if(cmdno == INTERACTIVE) prompt = FALSE; /* will be toggled */ if(cmdno == NONINTERACTIVE) prompt = TRUE; /* will be toggled */ return( toggle(command,word,&prompt, "Interactive mode on.\r\n", "Interactive mode off.\r\n") ); case LPWD: /* local working directory */ *command = '\0'; case LCD: /* change local directory */ if(*(stpblk(command))) lcd(command); /* * current directory */ kbprintf("Local directory is %s --> %s\r\n", (char *) getdef(),(char *) getpath(line)); return; case LRENAME: /* local RENAME */ if(question(command,100,"From: ")) return; getword(command,&xs[0]); if(question(command,100,"To: ")) return; getword(command,&xs[100]); lrename(); return; case LDELETE: /* local DEL */ case LDIR: /* local DIR */ case LLS: /* local DIR */ case LMKDIR: /* local MKDIR */ case LPROTECT: /* local PROTECT */ case LRMDIR: /* local RMDIR */ case LTYPE: /* local TYPE */ case LUNPROTECT: /* local UNPROTECT */ /* * Preprocessing */ if(!*(stpblk(command))) { switch(cmdno) { case LDELETE: case LPROTECT: case LTYPE: case LUNPROTECT: if(question(command,100,"File(s): ")) return; break; case LDIR: case LLS: lls(command); tstbrk(); return; case LRMDIR: case LMKDIR: if(question(command,100,"Directory(s): ")) return; break; } } /* * for each arg */ while(!tstbrk() && getword(command,word)) { /* * for each name */ switch(cmdno) { case LDELETE: ldelete(word); break; case LDIR: case LLS: lls(word); break; case LMKDIR: lmkdir(word); break; case LPROTECT: lprotect(word); break; case LRMDIR: lrmdir(word); break; case LTYPE: if((fp = rtopen(word,"r",0,0)) != NULL) { kbprintf("\r\nFile %s\r\n\r\n", word); while(fgetss(line,sizeof(line)-1,fp)!=NULL && !tstbrk()) { kbprintf("%s\r\n", line); } rtclose(fp); } else { kbprintf("\r\nFile %s not found\r\n", word); } kb_puts("\r\n"); break; case LUNPROTECT: lunprotect(word); break; } } return; case OPEN: /* open connection to host */ if(linked) { kb_puts("Already connected.\r\n"); return; } if(question(command,100,"To: ")) return; /* * host name */ getword(command,destname); /* * Open a connection to the machine named. */ if(ftpopen(0,destname,HFTP) == FALSE) return; /* * response from other end */ ftpreplies(&i); #ifdef DEBUGOPTION if(debug&0x10) { kb_puts("return from ftpreplies()\r\n"); } #endif if(tstbrk()) { return; } linked = TRUE; if(autologin) { strcpy(command,"user"); ftppi(command); } return; case SENDPORT: /* send PORT commands for each transfer */ return( toggle(command,word,&sendport, "Use of PORT cmds on.\r\n", "Use of PORT cmds off.\r\n") ); case STATUS: /* display status info */ if(linked) { kbprintf("Connected to %s\r\n",destname); } if(ftpfilemode == FASCII) { kb_puts("Transfer mode is ascii.\r\n"); } else { kb_puts("Transfer mode is binary.\r\n"); } if(bell) { kb_puts("Bell on.\r\n"); } else { kb_puts("Bell off.\r\n"); } #ifdef DEBUGOPTION if(debug) { kbprintf("Debugging on.(Debug=%d)\r\n",debug); } else { kb_puts("Debugging off.\r\n"); } #endif if(wild) { kb_puts("Filename wildcards enabled.\r\n"); } else { kb_puts("Filename wildcards disabled.\r\n"); } if(hash) { kb_puts("Hash-mark printing on.\r\n"); } else { kb_puts("Hash-mark printing off.\r\n"); } if(prompt) { kb_puts("Interactive prompting on.\r\n"); } else { kb_puts("Interactive prompting off.\r\n"); } if(sendport) { kb_puts("Sending of PORT commands on.\r\n"); } else { kb_puts("Sending of PORT cmds off.\r\n"); } if(verbose) { kb_puts("Verbose mode on.\r\n"); } else { kb_puts("Verbose mode off.\r\n"); } if(linked) { /* * send STAT command */ kb_puts("\r\nRemote status:\r\n"); i = verbose; verbose = TRUE; ftpdo("STAT",ofilename); verbose = i; } return; case VERBOSE: /* display informative messages */ return( toggle(command,word,&verbose, "Verbose mode on.\r\n", "Verbose mode off.\r\n") ); case VERSION: /* display current FTP version */ printtxt(vrstxt); return; default: /* The other commands valid only if connected */ if(!linked) { kb_puts("Not connected.\r\n"); return; } switch(cmdno) { case ASCII: /* transfer mode */ ftpdo("TYPE A",ofilename); return; case BGET: /* get file in binary mode */ curfilemode = setmode(FIMAGE,ofilename); if(question(command,100,"File: ")) return; /* * get file */ sprintf(cmndline,"RETR %s",command); fildev = 1; ftpdo(cmndline,ofilename); setmode(curfilemode,ofilename); return; case BINARY: /* binary mode */ ftpdo("TYPE I",ofilename); return; case BPUT: /* put file in binary mode */ curfilemode = setmode(FIMAGE,ofilename); /* * if no arg, get from user */ if(question(command,100,"File: ")) return; sprintf(cmndline,"STOR %s",command); ftpdo(cmndline,ofilename); setmode(curfilemode,ofilename); return; case CD: /* change remote directory */ /* * if no arg, get from user */ if(question(command,100,"To: ")) return; getword(command,word); /* * special case */ if(!strcmp(word,"..")) { /* * if CDUP understood */ if(ftpdo("CDUP",ofilename) != ERROR) return; kb_puts("Trying again...\r\n"); /* * try alternative */ if(ftpdo("XCUP",ofilename) != ERROR) return; kb_puts("Trying again...\r\n"); } /* * else try usual CWD */ sprintf(cmndline,"CWD %s",word); if(ftpdo(cmndline,ofilename) != ERROR) return; kb_puts("Trying again...\r\n"); /* * else try XCWD */ sprintf(cmndline,"XCWD %s",word); ftpdo(cmndline,ofilename); return; case CLOSE: /* drop connection */ ftpdo("QUIT",ofilename); linked = FALSE; return; case DEL: case RM: getword(command,word); if(question(word,100,"File: ")) return; if(prompt) { /* * check interactively */ kbprintf("Delete %s? ",word); rtresp(answer,20); if(tolower(*(stpblk(answer))) != 'y') return; } sprintf(cmndline,"DELE %s",word); ftpdo(cmndline,ofilename); return; case DIR: /* get list of remote files */ curfilemode = setmode(FASCII,ofilename); if(getword(command,word)) { /* * do DIR */ sprintf(cmndline,"LIST %s",word); ftpdo(cmndline,ofilename); } else { ftpdo("LIST",ofilename); } setmode(curfilemode,ofilename); return; case GET: case RECV: /* get remote file */ if(question(command,100,"File: ")) return; sprintf(cmndline,"RETR %s",command); fildev = 1; ftpdo(cmndline,ofilename); return; case LS: /* get remote file list - short */ curfilemode = setmode(FASCII,ofilename); if(getword(command,word)) { sprintf(cmndline,"NLST %s",word); ftpdo(cmndline,ofilename); } else { ftpdo("NLST",ofilename); } setmode(curfilemode,ofilename); return; case MDELETE: curfilemode = setmode(FASCII,ofilename); if(question(command,100,"Files: ")) return; /* * for each arg */ while(getword(command,word) && !fndbrk) { if(wild) { capture = TRUE; sprintf(cmndline,"NLST %s",word); ftpdo(cmndline,ofilename); capture = FALSE; } else { strcpy(captlist,word); } /* * for each name */ while(getnname(captlist,word) && !fndbrk) { if(prompt) { kbprintf("mdelete %s? ",word); if(rtresp(answer,20)) { /* * no more processing */ fndbrk = 1; break; } if(tolower(*(stpblk(answer))) != 'y') continue; } else { kbprintf( "Deleting file %s\r\n", word); } sprintf(cmndline,"DELE %s",word); if(ftpdo(cmndline,ofilename) == ABORT) { fndbrk = 1; break; } } } setmode(curfilemode,ofilename); return; case MDIR: /* remote multiple DIR */ curfilemode = setmode(FASCII,ofilename); if(question(command,100,"Directories: ")) return; /* * for each arg */ while(getword(command,word) && !fndbrk) { if(wild) { capture = TRUE; sprintf(cmndline,"NLST %s",word); ftpdo(cmndline,ofilename); capture = FALSE; } else { strcpy(captlist,word); } /* * for each name */ while(getnname(captlist,word) && !fndbrk) { if(prompt) { kbprintf("mdir %s? ",word); if(rtresp(answer,20)) { /* * no more processing */ fndbrk = 1; break; } if(tolower(*(stpblk(answer))) != 'y') continue; } /* * DIR */ sprintf(cmndline,"LIST %s",word); if(ftpdo(cmndline,ofilename) == ABORT) { fndbrk = 1; break; } } } setmode(curfilemode,ofilename); return; case MGET: /* get multiple files */ if(question(command,100,"Files: ")) return; /* * for each arg */ while(getword(command,word) && !fndbrk) { if(wild) { curfilemode=setmode(FASCII,ofilename); capture = TRUE; sprintf(cmndline,"NLST %s",word); ftpdo(cmndline,ofilename); setmode(curfilemode,ofilename); capture = FALSE; } else { strcpy(captlist,word); } /* * for each name */ while(getnname(captlist,word) && !fndbrk) { /* * name may have special chars */ q = (char *) lclfile(word); if(prompt) { kbprintf("mget %s as %s ? ", word,q); if(rtresp(answer,20)) { /* * no more processing */ fndbrk = 1; break; } if(tolower(*(stpblk(answer))) != 'y') continue; } else { kbprintf( "getting %s as %s\r\n", word,q); } sprintf(cmndline,"RETR \"%s\"", word); fildev = 1; if(ftpdo(cmndline,ofilename) == ABORT) { fndbrk = 1; break; } } } return; case MKDIR: /* create directory */ if(question(command,100,"Directory: ")) return; /* * try XMKD */ sprintf(cmndline,"XMKD %s",command); if(ftpdo(cmndline,ofilename) != ERROR) return; kb_puts("Trying again...\r\n"); /* * else try MKD */ sprintf(cmndline,"MKD %s",command); ftpdo(cmndline,ofilename); return; case MLS: curfilemode = setmode(FASCII,ofilename); if(question(command,100,"Directories: ")) return; /* * for each arg */ while(getword(command,word) && !fndbrk) { if(wild) { capture = TRUE; sprintf(cmndline,"NLST %s",word); ftpdo(cmndline,ofilename); capture = FALSE; } else { strcpy(captlist,word); } /* * for each name */ while(getnname(captlist,word) && !fndbrk) { if(prompt) { kbprintf("mls %s? ",word); if(rtresp(answer,20)) { /* * no more processing */ fndbrk = 1; break; } if(tolower(*(stpblk(answer))) != 'y') continue; } sprintf(cmndline,"NLST %s",word); if(ftpdo(cmndline,ofilename) == ABORT) { fndbrk = 1; break; } } } setmode(curfilemode,ofilename); return; case MODE: /* set stream mode */ getword(command,word); strlwr(word); if(strncmp(word,"stream",strlen(word))) { kb_puts( "We only support stream mode, sorry.\r\n"); } else { kb_puts("Mode is stream.\r\n"); } return; case MPUT: /* put multiple files */ if(question(command,100,"Files: ")) return; /* * for each arg */ while(getword(command,word) && !fndbrk) { /* * no names expanded yet */ p = NULL; /* * for each name */ do { /* * verify file exists / get first matching file */ if((p = filnam(word,p,wild)) == NULL) { lsterr(); continue; } if(prompt) { /* * check */ kbprintf("mput %s ?", p); if(rtresp(answer,20)) { /* * no more processing */ fndbrk = 1; break; } if(tolower(*(stpblk(answer))) != 'y') continue; } else { kbprintf("sending file %s\r\n", p); } /* * name may have special chars */ sprintf(cmndline, "STOR %s \"%s\"", p, (char *) rmtfile(p)); if(ftpdo(cmndline,ofilename) == ABORT) { fndbrk = 1; break; } } while(p != NULL && wild && !fndbrk); lastname(); } return; case PROTECT: /* set protection flag */ if(question(command,100,"File: ")) return; /* * set protection flag on a file */ sprintf(cmndline,"PSET %s",command); ftpdo(cmndline,ofilename); return; case PUT: case SEND: /* put file */ if(question(command,100,"File: ")) return; /* * put file */ sprintf(cmndline,"STOR %s",command); ftpdo(cmndline,ofilename); return; case PWD: i = verbose; verbose = TRUE; /* * try XPWD */ if(ftpdo("XPWD",ofilename) != ERROR) { verbose = i; return; } kb_puts("Trying again...\r\n"); /* * else try PWD */ ftpdo("PWD",ofilename); verbose = i; return; case QUOTE: if(question(command,100,"Command: ")) return; /* * send command */ ftpdo(command,ofilename); return; case REMOTEHELP: /* get help */ i = verbose; verbose = TRUE; if(*(stpblk(command))) { /* * for specific command */ sprintf(cmndline,"HELP %s",command); ftpdo(cmndline,ofilename); } else { ftpdo("HELP",ofilename); } verbose = i; return; case RENAME: /* rename remote file */ if(question(command,100,"From: ")) return; getword(command,word); /* * send rename from name */ sprintf(cmndline,"RNFR %s",word); if(ftpdo(cmndline,ofilename) != INCOMPLETE) return; if(question(command,100,"To: ")) { ftpdo("ABOR",ofilename); return; } /* * send rename to name */ sprintf(cmndline,"RNTO %s",command); ftpdo(cmndline,ofilename); return; case RMDIR: /* remove remote dir */ if(question(command,100,"Directory: ")) return; /* * try XRMD */ sprintf(cmndline,"XRMD %s",command); if(ftpdo(cmndline,ofilename) != ERROR) return; kb_puts("Trying again...\r\n"); /* * try RMD */ sprintf(cmndline,"RMD %s",command); ftpdo(cmndline,ofilename); return; case STRUCT: /* set structure type - only file */ getword(command,word); strlwr(word); if(strncmp(word,"file",strlen(word))) { kb_puts( "We only support file structure, sorry.\r\n"); } else { kb_puts("Structure is file.\r\n"); } return; case SYSTEM: /* get remote system type */ i = verbose; verbose = TRUE; ftpdo("SYST",ofilename); verbose = i; return; case TYPE: /* type a remote file */ if(question(command,100,"File: ")) return; getword(command,word); sprintf(cmndline,"RETR %s tt:tt.tt",word); fildev = 0; ftpdo(cmndline,ofilename); return; case UNPROTECT: /* clear protection flag */ if(question(command,100,"File: ")) return; /* * clear protection flag on a file */ sprintf(cmndline,"PCLR %s",command); ftpdo(cmndline,ofilename); return; case USER: /* login to remote machine */ if(question(command,100,"Username: ")) return; /* * username */ sprintf(cmndline,"USER %s",command); if(ftpdo(cmndline,ofilename) == TRUE) return; /* * password */ kb_puts("Password: "); if(ftpgets(command,100,0) == ABORT) return; sprintf(cmndline,"PASS %s",command); if(ftpdo(cmndline,ofilename) == INCOMPLETE) { /* * if account needed */ *command = '\0'; if(question(command,100,"Account: ")) return; sprintf(cmndline,"ACCT %s",command); ftpdo(cmndline,ofilename); } return; default: /* unknown command */ kbprintf( "***Program error: Unknown command no: %d\r\n",cmdno); break; } } } /* * setmode * * set the transfer mode * and return old mode */ static int setmode(mode,ofilename) int mode; char *ofilename; { register int cmode; cmode = ftpfilemode; switch(mode) { default: kb_puts("Invalid ftpfilemode, defaulting to ASCII\r\n"); case FASCII: if (cmode != FASCII) ftpdo("TYPE A",ofilename); break; case FIMAGE: if (cmode != FIMAGE) ftpdo("TYPE I",ofilename); break; } return(cmode); } /* * ftpopen * * open an FTP connection */ static int ftpopen(lpnum,dst,port) int lpnum,port; char *dst; { register struct socket *skt; int flag; int cl,ev,dat; /* * Open a control connection */ ftpcskt = addsess(lpnum,dst,port); if(ftpcskt >= 0) { flag = 1; } else { flag = 0; } while(flag && !tstbrk()) { if(Sgetevent(ABORTCLASS,&cl,&dat)) ftpexit(ABORT); errhandle(); ev = Sgetevent(CONCLASS,&cl,&dat); switch(ev) { case CONOPEN: /* * Log the Session */ sprintf(printline,"FTP: %s", destname); logsession(dat,printline); return(TRUE); case CONCLOSE: case CONFAIL: flag = 0; break; default: if(ev) { Stmrset(cl,ev,dat,1); } else { suspnd(0); } } } /* * error on open */ skclose(ftpcskt); ftpcskt = skrelease(ftpcskt,1); skclose(ftpdskt); ftpdskt = skrelease(ftpdskt,1); errhandle(); kbprintf("Unable to connect to %s\r\n",dst); return(FALSE); } /* * ftpport * * setup the appropriate listening port * the default port HFTP-1 should be used only for single user mode * TCPIP will select a unique port if the default port (skt->sktport) * is zero, else the specified port will be used. * return the socket number if ok, else return -1 on error. */ static int ftpport() { register struct socket *skt; register char *myip; int sknum,port,rcode; /* * Create socket for data connection */ sknum = socket(1); if(sknum == -1) return(-1); #ifdef DEBUGOPTION if(debug&0x08) { kbprintf("ftpport(): sknum = %d\r\n", sknum); } #endif /* * default port */ if(!sendport) { listen(sknum,HFTP-1); return(sknum); } #ifdef DEBUGOPTION if(debug&0x08) { kb_puts("ftpport(): before dumpcon() call \r\n"); } #endif dumpcon(); /* * Setup listener */ port = listen(sknum,0); /* * get my ip number */ skt = (struct socket *) mapskt(sknum); myip = skt->tcpout.i.ipsource; /* * full port number */ sprintf(printline,"PORT %d,%d,%d,%d,%d,%d\r\n", *(myip+0) & 0xFF, *(myip+1) & 0xFF, *(myip+2) & 0xFF, *(myip+3) & 0xFF, (port>>8) & 0xFF, port & 0xFF); #ifdef DEBUGOPTION if(debug&0x02) { kb_puts(printline); } #endif /* * send PORT command */ skwrite(ftpcskt,printline,strlen(printline)); skenque(ftpcskt,1); /* * get response */ #ifdef DEBUGOPTION if(debug&0x08) { kb_puts("ftpport(): before ftpreplies() call \r\n"); } #endif ftpreplies(&rcode); #ifdef DEBUGOPTION if(debug&(0x08|0x10)) { kb_puts("return from ftpreplies()\r\n"); } #endif /* * socket number */ return(sknum); } /* * ftpdo * * Do whatever command is sent from the user interface using * userftpd, the background file handler * Returns code from ftpreplies */ static int ftpdo(str,ofile) char *str,*ofile; { int i,rcode; char name[50],name2[50]; /* * command to upper case */ for(i=0; i<4; i++) { str[i] = toupper(str[i]); } /* * put file */ if(!strncmp(str,"STOR",4)) { /* * first arg - local file */ getword(&str[5],name); /* * check for second argument */ if(!str[5]) { /* * if only one argument */ strcpy(&str[5],rmtfile(name)); } else { /* * second arg - removes quotes etc. */ getword(&str[5],name2); /* * copy back into command */ strcpy(&str[5],name2); } /* * open local file */ ftpfh = rtopen(name,"rn",0,0); if(ftpfh == NULL) { kb_puts(" Cannot open file to transfer.\r\n"); return(-1); } /* * open data connection */ #ifdef DEBUGOPTION if(debug&0x04) { kb_puts("ftpdo(STOR): before calling ftpport()\r\n"); } #endif ftpdskt = ftpport(); if(ftpdskt == -1) return(-1); ftpstate = 20; #ifdef DEBUGOPTION if(debug&0x04) { kb_puts("ftpdo(STOR): after calling ftpport()\r\n"); } #endif } else if(!strncmp(str,"RETR",4)) { /* * get remote file */ getword(&str[5],name); if(str[5]) { /* * two args present */ getword(&str[5],name2); /* * open local file */ ftpfh = rtopen(name2,"wn",fildev,fromtty&&prompt); } else { /* * local name same as remote */ ftpfh = rtopen(name,"wn",fildev,fromtty&&prompt); } if(ftpfh == -1) return(-1); if(ftpfh == NULL) { kbprintf("Cannot open file to receive: %s\r\n",name); return(-1); } /* * put remote name back into command */ strcpy(&str[5],name); /* * open data connection */ #ifdef DEBUGOPTION if(debug&0x04) { kb_puts("ftpdo(RETR): before calling ftpport()\r\n"); } #endif ftpdskt = ftpport(); if(ftpdskt == -1) return(-1); ftpstate = 30; #ifdef DEBUGOPTION if(debug&0x04) { kb_puts("ftpdo(RETR): after calling ftpport()\r\n"); } #endif } else if(!strncmp(str,"LIST",4) || !strncmp(str,"NLST",4)) { /* * where to put incoming data */ if(capture) { captlist[0] = '\0'; stopcapture = FALSE; } /* * data connection */ #ifdef DEBUGOPTION if(debug&0x04) { kb_puts("ftpdo(LIST/NLST): before calling ftpport()\r\n"); } #endif ftpdskt = ftpport(); if(ftpdskt == -1) return(-1); ftpstate = 40; #ifdef DEBUGOPTION if(debug&0x04) { kb_puts("ftpdo(LIST/NLST): after calling ftpport()\r\n"); } #endif } else if(!strncmp(str,"TYPE",4)) { if(toupper(str[5]) == 'I') { /* * remember mode */ ftpfilemode = FIMAGE; } else if(toupper(str[5]) == 'A') { ftpfilemode = FASCII; } } /* * clear command connection */ dumpcon(); /* * send command */ skwrite(ftpcskt,str,strlen(str)); /* * terminates command */ skwrite(ftpcskt,"\r\n",2); skenque(ftpcskt,1); if(!capture && ofile[0]) { /* * command redirected */ if((ftpstate != 20) && (ftpstate != 30)) { /* * not get or put */ if(ftpdskt == -1) { rtclose(ftpfh); ftpfh = NULL; } else { ftpfh = rtopen(ofile,"wn",1,fromtty&&prompt); if(ftpfh == NULL) kb_puts( " Cannot open output file.\r\n"); if(ftpfh == NULL || ftpfh == -1) { ftpfh = NULL; ofile[0] = '\0'; } /* * act as get, since data goes into file */ ftpstate = 30; } } } #ifdef DEBUGOPTION if(debug&0x02) { /* * show command sent */ kbprintf("---> %s\r\n",str); } #endif /* * get remote response */ #ifdef DEBUGOPTION if(debug&0x04) { kb_puts("ftpdo(): before ftpreplies() call\r\n"); } #endif i = ftpreplies(&rcode); #ifdef DEBUGOPTION if(debug&(0x04|0x10)) { kb_puts("return from ftpreplies()\r\n"); } #endif if((i == NONE) && strncmp(str,"QUIT",4)) { /* * unexpected connection drop */ kb_puts("lost connection\r\n"); linked = FALSE; } if(i == ABORT || i == NONE || i == ERROR) { /* * if error, no transfer */ skclose(ftpdskt); ftpdskt = skrelease(ftpdskt,1); ftpstate = 0; rtclose(ftpfh); ftpfh = NULL; /* * dump any remaining comments */ dumpcon(); } return(i); } /* * ftpreplies * * get responses to commands to server * return TRUE on successful completion, * INCOMPLETE if more commands needed for operation, * NONE on lost connection, ABORT on an abort, and ERROR on failure * PRELIMINARY and TRANSIENT responses wait for completion */ static int ftpreplies(rcode) int *rcode; { int abrtcnt,cnt,digit,ev,j; #ifdef DEBUGOPTION if(debug&0x10) { kb_puts("entering ftpreplies()\r\n"); } #endif abrtcnt = 0; j = 0; loop: while(1) { /* * get line from remote host */ cnt = rgetline(); #ifdef DEBUGOPTION if(debug&0x10 && !(debug&0x20)) { kbprintf("cnt=rgetline(): =%d\r\n s=%s\r\n",cnt,s); } #endif if(cnt == NONE) /* * lost connection */ return(NONE); if(cnt == ABORT) { /* * user abort */ if(ftpabort(&abrtcnt) == ABORT) return(ABORT); goto loop; } if(!sscanf(s,"%d",rcode)) /* * continuation line */ *rcode = -1; /* * informative/error message or display on */ if(verbose || (*rcode == -1) || (*rcode >= 500)) filter(cnt); if((*rcode/100) == 2) { /* * wait till transfers complete */ while(ftpdskt >= 0) { ev = checkevent(); #ifdef DEBUGOPTION if(debug&0x10) { kbprintf("checkevent()=%d\r\n",ev); } #endif if(ev == NONE) { /* * lost connection */ return(NONE); } if(ev == ABORT) { /* * user abort */ if(ftpabort(&abrtcnt) == ABORT) return(ABORT); } /* * wait a while */ suspnd(6); } } #ifdef DEBUGOPTION if(debug&0x10) { kbprintf("*rcode=%d\r\n", *rcode); } #endif if(s[3] == '-') { /* * line with continuations * remember end code */ j = *rcode; continue; } else if(j) { if(*rcode == j) { /* * end of continuation */ j = 0; } else { continue; } } /* * first digit */ digit = (int)(*rcode/100); if(abrtcnt) { switch(digit) { case 1: /* preliminary */ case 4: /* transient negative completion */ continue; default: kb_puts( "Server response not understood.\r\n"); kb_puts("Terminating command\r\n"); case 2: /* positive completion */ case 3: /* intermediate */ case 5: /* Permanent negative completion */ return(ABORT); } } else { switch(digit) { case 1: /* preliminary */ case 4: /* transient negative completion */ continue; case 2: /* positive completion */ return(TRUE); case 3: /* intermediate */ return(INCOMPLETE); default: kb_puts( "Server response not understood.\r\n"); kb_puts("Terminating command\r\n"); case 5: /* Permanent negative completion */ return(ERROR); } } } } /* * ftpabort * * attempt to abort FTP operation * return ABORT on unconditional abort */ static int ftpabort(i) int *i; { finished = TRUE; switch(ftpstate) { default: /* Invalid states */ case 0: break; case 20: /* finished == TRUE */ case 21: /* will terminate transfers */ case 22: break; case 30: case 31: case 40: case 41: /* * Send the abort as an urgent message */ sksendwait(ftpcskt,1,(long) SENDWAIT); skwurgent(ftpcskt,1); /* IAC IP IAC DM */ skwrite(ftpcskt,"\377\364\377\362",4); skwrite(ftpcskt,"ABOR\r\n",6); sksendwait(ftpcskt,1,(long) SENDWAIT); skwurgent(ftpcskt,0); break; } *i += 1; if(*i > 2) { if(fromfp != NULL) { fclose(fromfp); fromfp = NULL; fromtty = TRUE; kb_puts("\r\nCommand File Input Aborted"); } kb_puts("\r\nUnconditonal ABORT\r\n"); return(ABORT); } else { kb_puts("\r\nAttempting to ABORT operation ...\r\n"); return(0); } } /* * rgetline - get a line from remote server * * return ABORT on an abort, NONE on lost connection, * length of received line on success */ static int rgetline() { int cnt,i,ev; #ifdef DEBUGOPTION if(debug&0x20) { kb_puts("entering rgetline()\r\n"); } #endif i = 0; while(1) { ev = checkevent(); #ifdef DEBUGOPTION if(debug&0x20) { kbprintf("checkevent()=%d\r\n", ev); } #endif switch(ev) { case NONE: /* lost connection */ skdeque(ftpcskt); case ABORT: /* abort */ #ifdef DEBUGOPTION if(debug&0x20) { kb_puts("leaving rgetline()\r\n"); } #endif return(ev); case HAVEDATA: /* * get some from queue */ while(1) { cnt = skread(ftpcskt,&s[i],1); if(!cnt) /* * nothing available */ break; if(s[i++] == '\n') { /* * end of line */ s[i] = '\0'; #ifdef DEBUGOPTION if(debug&0x20) { kbprintf( "i=%d, s=%s\r\nleaving rgetline()\r\n", i,s); } #endif skdeque(ftpcskt); /* * return line length */ return(i); } if(i > GBUFSIZE - 2) i = GBUFSIZE - 2; } break; default: /* ignore other events */ suspnd(10); break; } } } /* * userftpd * * FTP receive and send file functions */ static VOID userftpd() { register int fcnt,i; int e1,e2,r1,r2; register double etime,rate; #ifdef DEBUGOPTION if(debug&0x40) { if(ftpstate) { kbprintf("userftpd(%d):", ftpstate); } } #endif fcnt = 0; switch(ftpstate) { default: /* unknown */ break; case 40: /* start LIST */ if(sktest(ftpdskt)) break; /* * Initialize parameters */ tbytes = 0L; /* * connection made */ start = cticks(NULL); ftpstate = 41; case 41: /* get started */ if(capture && !stopcapture) { /* * into captlist */ fcnt = skread(ftpdskt,xs,READSIZE); /* * make certain a negative length * string is not appended */ if(fcnt>0) { skdeque(ftpdskt); if(strlen(captlist)+fcnt >= BUFFERS-1) { /* * full */ kb_puts("Error: capture list too long\r\n"); kb_puts(" m___ operation aborted\r\n"); captlist[0] = '\0'; stopcapture = TRUE; } else { /* * append */ strncat(captlist,xs,fcnt); } } #ifdef DEBUGOPTION if(debug&0x40) { kbprintf( " fcnt %d tbytes %ld strlen(captlist) %d\r\n", fcnt,tbytes,strlen(captlist)); } #endif } else { fcnt = skread(ftpdskt,xs,READSIZE); if(fcnt>0) { skdeque(ftpdskt); xs[fcnt] = '\0'; if(!stopcapture) kb_puts(xs); } } if(fcnt>0) /* * how much */ tbytes += fcnt; #ifdef DEBUGOPTION if(debug&0x40) { kbprintf(" tbytes %ld\r\n captlist " ,tbytes); kb_puts(captlist); } #endif break; case 30: /* receive */ if(sktest(ftpdskt)) break; /* * Initialize parameters */ len = 0; xp = 0; hashcnt = 0; hashnum = 0; tbytes = 0L; /* * connection made */ start = cticks(NULL); ftpstate = 31; case 31: /* * file has already been opened, * take everything from the connection * and place into the open file: ftpfh */ /* * wait until xs is full * before writing to disk */ if(len <= 0) { if(xp) { if(ftpfh != NULL) fwrite(xs,1,xp,ftpfh); xp = 0; } /* * expected or desired len to go */ len = BUFFERS; } /* * how much to read */ if(len < BUFFERS) { i = len; } else { i = BUFFERS; } fcnt = skread(ftpdskt,&xs[xp],i); #ifdef DEBUGOPTION if(debug&0x40) { kbprintf(" len %d xp %d fcnt %d", len,xp,fcnt); } #endif /* * adjust counts */ if(fcnt>0) { skdeque(ftpdskt); len -= fcnt; xp += fcnt; hashcnt += fcnt; tbytes += fcnt; } /* * connection closed */ if(fcnt<0) { /* * write last block */ if(ftpfh != NULL) { fwrite(xs,1,xp,ftpfh); rtclose(ftpfh); ftpfh = NULL; } } /* * hash mark printing */ while(hash && hashcnt >= HASHSIZE) { hashcnt -= HASHSIZE; if(++hashnum >= 75) { kb_puts("#\r\n"); hashnum = 0; } else { kb_out('#'); } } break; case 20: /* send */ if(sktest(ftpdskt)) break; /* * Initialize parameters */ finished = FALSE; towrite = 0; xp = 0; hashcnt = 0; hashnum = 0; tbytes = 0L; /* * connection made */ start = cticks(NULL); ftpstate = 21; case 21: /* * transfer file(s) to the * other host via ftp request * file is already open=ftpfh */ if(towrite <= xp && finished == FALSE) { /* * need to read again */ fcnt = fread(xs,1,READSIZE,ftpfh); if(ftpfilemode == FASCII) { xs[fcnt] = '\0'; fcnt = strlen(xs); } if(fcnt == 0) finished = TRUE; towrite = fcnt; xp = 0; } fcnt = towrite - xp; if(fcnt>0) { fcnt = skwrite(ftpdskt,&xs[xp],fcnt); } if(fcnt>0) { skenque(ftpdskt,1); /* * send successful, adjust counts */ xp += fcnt; hashcnt += fcnt; tbytes += fcnt; } #ifdef DEBUGOPTION if(debug&0x40) { kbprintf(" finished %d fcnt %d xp %d towrite %d", finished,fcnt,xp,towrite); } #endif /* * hash printing */ while(hash && hashcnt >= HASHSIZE) { hashcnt -= HASHSIZE; if(++hashnum >= 75) { kb_puts("#\r\n"); hashnum = 1; } else { kb_out('#'); } } /* * done if: the file * is all read from disk * and all sent or other side * has ruined connection */ if((towrite <= xp && finished == TRUE) || sktest(ftpdskt)) { ftpstate = 22; } if(ftpstate == 21) break; case 22: /* send done * wait for other side to accept * everything and then start close */ if(0 >= (i = skenque(ftpdskt,1)) || sktest(ftpdskt)) { fcnt = -1; } #ifdef DEBUGOPTION if(debug&0x40) { kbprintf(" skenque = %d", i); } #endif break; } #ifdef DEBUGOPTION if(debug&0x40) { if(ftpstate) { kb_nline(); } } #endif /* * after processing from connection, * if the connection is closed, * reset up shop. */ if(fcnt>0) { /* * continue processing */ suspnd(-1); } else if(fcnt<0) { /* * connection lost */ if(ftpfh != NULL) { /* * close file */ rtclose(ftpfh); ftpfh = NULL; } /* * done */ ftpstate = 0; fcnt = 0; if(hash) kb_nline(); /* * how long to transfer */ if(verbose) { /* * Time calculation */ etime = ((double) elapsed(start)) / ((double) TICKSPERSEC); e1 = etime; e2 = (etime - ((double) e1)) * 10.0; if(!e1) { e1 = 1; e2 = 0; } etime = ((double) e1) + (((double) e2) / 10.0); /* * Rate calculation */ rate = ((double) tbytes) /(etime * 1000.0); r1 = rate; r2 = (rate - ((double) r1)) * 1000.0; kbprintf( "Transferred %ld bytes in %d.%d seconds(%d.%03d kbytes/sec)\r\n", tbytes,e1,e2,r1,r2); } /* * close connection */ skclose(ftpdskt); if(bell) kb_out(7); } /* * Release socket when closed */ if(ftpdskt >= 0) { #ifdef DEBUGOPTION if(debug&0x40) { kbprintf("userftpd : ftpdskt = %d, state = %d\r\n", ftpdskt,skstate(ftpdskt)); } #endif if((ftpdskt = skrelease(ftpdskt,0)) < 0) ftpstate = 0; } } /* * getword: remove a word from a string. Things within quotes are * assumed to be one word. * return TRUE on success, FALSE on end of string */ static int getword(string,word) char *string; register char *word; { register char *p; register int i; char *q; i = 0; #ifdef DEBUGOPTION if(debug&0x80) { kbprintf("getword: string is %s\r\n",string); } #endif /* * skip leading blanks */ p = stpblk(string); if(!(*p)) { /* * no words in string */ word[0] = '\0'; return(FALSE); } if(*p == '!') { /* * ! is a word */ word[0] = *p; word[1] = '\0'; strcpy(string,++p); return(TRUE); } if(*p == '\"') { /* * word delimited by quotes */ while(p[++i] && p[i] != '\"') word[i-1] = p[i]; word[i-1] = '\0'; if(!p[i]) { kb_puts("Missing \". Assumed at end of string.\r\n"); } else { i++; } q = p+i; } else { /* * get word, max len 50 */ q = stptok(p, word, 50, " \t\r\n"); } /* * remove trailing blanks */ p = stpblk(q); /* * remove extracted stuff */ strcpy(string,p); return(TRUE); } /* * checkoredir: check for output redirection. If the command contains a * >, assume a filename follows and extract it. Remove the redirection * from the original command. * return TRUE if redirection specified, FALSE otherwise */ static int checkoredir(command,filename) char *command,*filename; { int i; filename[0] = '\0'; /* * process command part */ for(i=0;(command[i] != '>'); i++) { if(!command[i]) /* * no redirection */ return(FALSE); } /* * get redirected filename */ getword(&command[i+1],filename); command[i] = '\0'; return(TRUE); } /* * finduniq: * * find name that is a unique prefix of one of the entries in * a list. Return position of the entry, * NONE if none, AMBIGUOUS if more than one. */ static int finduniq(name,list,listsize) char *name, *list[]; int listsize; { int i,j,ilen; j = NONE; ilen = strlen(name); for(i=0; i or */ static int getnname(string,word) register char *string,*word; { register char *str; #ifdef DEBUGOPTION register int i; if(debug&0x100) { kbprintf("getnname: string is %s\r\n",string); for(i=0; i<40; i++) tt_out(string[i]); } #endif str = string; /* * skip initial newlines */ while((*string == '\n') || (*string == '\r')) string++; if(!(*string)) /* * end of captlist */ return(FALSE); while((*string != '\n') && (*string != '\r') && (*string)) *(word++) = *(string++); /* * skip trailing newline */ while((*string == '\n') || (*string == '\r')) string++; *word = '\0'; strcpy(str,string); #ifdef DEBUGOPTION if(debug&0x100) { kbprintf("getnname: string is %s\r\n",str); } #endif return(TRUE); } static VOID strlwr(st) register char *st; { while(*st) { *st = tolower(*st); *st++; } } static char *stptok( p, toword, ilen, delim) register char *p; char *toword; int ilen; char *delim; { register char *adv; register int i; int j,end; adv = toword; end = 0; j = strlen(delim); do { for(i=0; i= (toword+ilen-1)) end++; *adv++=*p++; } } while(!end); *adv='\0'; return(p); } char *stpblk(ch) register char *ch; { while(*ch == ' ' || *ch == '\t') ch++; return(ch); } /* * chkusr * * Check the password file for the user/password * combination. An inaccessable password file * results in an invalid return. * * If the user/password are validated and * the user has the rquired privelege, * then a valid return is made. * * Returns valid(0)/invalid(1) */ int chkusr() { FILE *fp; struct userblock user; char username[USERPASSLEN+2]; char password[USERPASSLEN+2]; char command[100]; char word[100]; /* * username */ if(question(command,100,"Username: ")) return(1); getword(command,word); username[0] = '\0'; strncat(username,word,USERPASSLEN); strlwr(username); /* * password */ if(!(*stpblk(command))) { kb_puts("Password: "); if(ftpgets(command,100,0) == ABORT) return(1); } getword(command,word); password[0] = '\0'; strncat(password,word,USERPASSLEN); strlwr(password); /* * Check username / password file */ if(NULL==(fp = rtopen(pass,"rn",0,0))) { return(1); } while (NULL != fread(&user,sizeof(struct userblock),1,fp)) { /* * does username / password check ? */ if(!strncmp(username,&user.username,USERPASSLEN) && (user.userflag[0]&PASSNOTREQUIRED || Scompass(password,&user.password)) ) { rtclose(fp); /* * Check Telnet privileges */ if(!(user.userflag[1] & LFTP_PRIV)) { kb_puts("No Privilege for FTP\r\n"); return(1); } /* * User valid */ return(0); } } kb_puts("Invalid Username / Password.\r\n"); rtclose(fp); return(1); } /* * Scompass ( ps, en ) * * Compute and check the encrypted password */ int Scompass(ps,en) char *ps,*en; { int i,ck; char *p,c; ck = 0; p = ps; /* * checksum the string */ while (*p) ck += *p++; c = ck; /* * XOR with checksum */ i = USERPASSLEN; while (i--) { if((((*ps ^ c)|32)&127)!=*en) return(0); /* * increment checksum to hide length */ if(*ps) { ps++; } else { c++; } en++; } return(1); } /* * printout text */ static VOID printtxt(txt) char **txt; { char **dp; for (dp=txt; *dp; dp++) { kb_puts(*dp); kb_nline(); } }