1666 lines · 30.0 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include <bio.h>#include <ip.h>#include <mp.h>#include <libsec.h>#include <auth.h>#include <fcall.h>#include <ctype.h>#include <String.h>#include "ftpfs.h" enum{	/* return codes */	Extra=		1,	Success=	2,	Incomplete=	3,	TempFail=	4,	PermFail=	5,	Impossible=	6,}; Node	*remdir;		/* current directory on remote machine */Node	*remroot;		/* root directory on remote machine */ int	ctlfd;			/* fd for control connection */Biobuf	ctlin;			/* input buffer for control connection */Biobuf	stdin;			/* input buffer for standard input */Biobuf	dbuf;			/* buffer for data connection */char	msg[512];		/* buffer for replies */char	net[Maxpath];		/* network for connections */int	listenfd;		/* fd to listen on for connections */char	netdir[Maxpath];int	os, defos;char	topsdir[64];		/* name of listed directory for TOPS */String	*remrootpath;	/* path on remote side to remote root */char	*user;int	nopassive;long	lastsend;extern int usetls; static void	sendrequest(char*, char*);static int	getreply(Biobuf*, char*, int, int);static int	active(int, Biobuf**, char*, char*);static int	passive(int, Biobuf**, char*, char*);static int	data(int, Biobuf**, char*, char*);static int	port(void);static void	ascii(void);static void	image(void);static void	unixpath(Node*, String*);static void	vmspath(Node*, String*);static void	mvspath(Node*, String*);static Node*	vmsdir(char*);static int	getpassword(char*, char*);static int	nw_mode(char dirlet, char *s); /* *  connect to remote server, default network is "tcp/ip" */voidhello(char *dest){	char *p;	char dir[Maxpath];	TLSconn conn; 	Binit(&stdin, 0, OREAD);	/* init for later use */ 	ctlfd = dial(netmkaddr(dest, "tcp", "ftp"), 0, dir, 0);	if(ctlfd < 0){		fprint(2, "can't dial %s: %r\n", dest);		exits("dialing");	}			Binit(&ctlin, ctlfd, OREAD); 	/* remember network for the data connections */	p = strrchr(dir+1, '/');	if(p == 0)		fatal("wrong dial(2) linked with ftp");	*p = 0;	safecpy(net, dir, sizeof(net)); 	/* wait for hello from other side */	if(getreply(&ctlin, msg, sizeof(msg), 1) != Success)		fatal("bad hello");	if(strstr(msg, "Plan 9"))		os = Plan9; 	if(usetls){		sendrequest("AUTH", "TLS");		if(getreply(&ctlin, msg, sizeof(msg), 1) != Success)			fatal("bad auth tls"); 		ctlfd = tlsClient(ctlfd, &conn);		if(ctlfd < 0)			fatal("starting tls: %r");		free(conn.cert); 		Binit(&ctlin, ctlfd, OREAD); 		sendrequest("PBSZ", "0");		if(getreply(&ctlin, msg, sizeof(msg), 1) != Success)			fatal("bad pbsz 0");		sendrequest("PROT", "P");		if(getreply(&ctlin, msg, sizeof(msg), 1) != Success)			fatal("bad prot p");	}} /* *  login to remote system */voidrlogin(char *rsys, char *keyspec){	char *line;	char pass[128];	UserPasswd *up; 	up = nil;	for(;;){		if(up == nil && os != Plan9)			up = auth_getuserpasswd(auth_getkey, "proto=pass server=%s service=ftp %s", rsys, keyspec);		if(up != nil){			sendrequest("USER", up->user);		} else {			print("User[default = %s]: ", user);			line = Brdline(&stdin, '\n');			if(line == 0)				exits(0);			line[Blinelen(&stdin)-1] = 0;			if(*line){				free(user);				user = strdup(line);			}			sendrequest("USER", user);		}		switch(getreply(&ctlin, msg, sizeof(msg), 1)){		case Success:			goto out;		case Incomplete:			break;		case TempFail:		case PermFail:			continue;		} 		if(up != nil){			sendrequest("PASS", up->passwd);		} else {			if(getpassword(pass, pass+sizeof(pass)) < 0)				exits(0);			sendrequest("PASS", pass);		}		if(getreply(&ctlin, msg, sizeof(msg), 1) == Success){			if(strstr(msg, "Sess#"))				defos = MVS;			break;		}	}out:	if(up != nil){		memset(up, 0, sizeof(*up));		free(up);	}} /* *  login to remote system with given user name and password. */voidclogin(char *cuser, char *cpassword){	free(user);	user = strdup(cuser);	if (strcmp(user, "anonymous") != 0 &&	    strcmp(user, "ftp") != 0)		fatal("User must be 'anonymous' or 'ftp'");	sendrequest("USER", user);	switch(getreply(&ctlin, msg, sizeof(msg), 1)){	case Success:		return;	case Incomplete:		break;	case TempFail:	case PermFail:		fatal("login failed");	}	if (cpassword == 0)		fatal("password needed");	sendrequest("PASS", cpassword);	if(getreply(&ctlin, msg, sizeof(msg), 1) != Success)		fatal("password failed");	if(strstr(msg, "Sess#"))		defos = MVS;	return;} /* *  find out about the other side.  go to it's root if requested.  set *  image mode if a Plan9 system. */voidpreamble(char *mountroot){	char *p, *ep;	int rv;	OS *o; 	/*	 *  create a root directory mirror	 */	remroot = newnode(0, s_copy("/"));	remroot->d->qid.type = QTDIR;	remroot->d->mode = DMDIR|0777;	remdir = remroot; 	/*	 *  get system type	 */	sendrequest("SYST", nil);	switch(getreply(&ctlin, msg, sizeof(msg), 1)){	case Success:		for(o = oslist; o->os != Unknown; o++)			if(strncmp(msg+4, o->name, strlen(o->name)) == 0)				break;		os = o->os;		if(os == NT)			os = Unix;		break;	default:		os = defos;		break;	}	if(os == Unknown)		os = defos; 	remrootpath = s_reset(remrootpath);	switch(os){	case NetWare:              /*               * Request long, rather than 8.3 filenames,               * where the Servers & Volume support them.               */              sendrequest("SITE LONG", nil);              getreply(&ctlin, msg, sizeof(msg), 0);              /* FALL THRU */	case Unix:	case Plan9:		/*		 *  go to the remote root, if asked		 */		if(mountroot){			sendrequest("CWD", mountroot);			getreply(&ctlin, msg, sizeof(msg), 0);		} else {			s_append(remrootpath, "/usr/");			s_append(remrootpath, user);		} 		/*		 *  get the root directory		 */		sendrequest("PWD", nil);		rv = getreply(&ctlin, msg, sizeof(msg), 1);		if(rv == PermFail){			sendrequest("XPWD", nil);			rv = getreply(&ctlin, msg, sizeof(msg), 1);		}		if(rv == Success){			p = strchr(msg, '"');			if(p){				p++;				ep = strchr(p, '"');				if(ep){					*ep = 0;					s_append(s_reset(remrootpath), p);				}			}		} 		break;	case Tops:	case VM:		/*		 *  top directory is a figment of our imagination.		 *  make it permanently cached & valid.		 */		CACHED(remroot);		VALID(remroot);		remroot->d->atime = time(0) + 100000; 		/*		 *  no initial directory.  We are in the		 *  imaginary root.		 */		remdir = newtopsdir("???");		topsdir[0] = 0;		if(os == Tops && readdir(remdir) >= 0){			CACHED(remdir);			if(*topsdir)				remdir->remname = s_copy(topsdir);			VALID(remdir);		}		break;	case VMS:		/*		 *  top directory is a figment of our imagination.		 *  make it permanently cached & valid.		 */		CACHED(remroot);		VALID(remroot);		remroot->d->atime = time(0) + 100000; 		/*		 *  get current directory		 */		sendrequest("PWD", nil);		rv = getreply(&ctlin, msg, sizeof(msg), 1);		if(rv == PermFail){			sendrequest("XPWD", nil);			rv = getreply(&ctlin, msg, sizeof(msg), 1);		}		if(rv == Success){			p = strchr(msg, '"');			if(p){				p++;				ep = strchr(p, '"');				if(ep){					*ep = 0;					remroot = remdir = vmsdir(p);				}			}		}		break;	case MVS:		usenlst = 1;		break;	} 	if(os == Plan9)		image();} static voidascii(void){	sendrequest("TYPE A", nil);	switch(getreply(&ctlin, msg, sizeof(msg), 0)){	case Success:		break;	default:		fatal("can't set type to ascii");	}} static voidimage(void){	sendrequest("TYPE I", nil);	switch(getreply(&ctlin, msg, sizeof(msg), 0)){	case Success:		break;	default:		fatal("can't set type to image/binary");	}} /* *  decode the time fields, return seconds since epoch began */char *monthchars = "janfebmaraprmayjunjulaugsepoctnovdec";static Tm now; static ulongcracktime(char *month, char *day, char *yr, char *hms){	Tm tm;	int i;	char *p;  	/* default time */	if(now.year == 0)		now = *localtime(time(0));	tm = now;	tm.yday = 0; 	/* convert ascii month to a number twixt 1 and 12 */	if(*month >= '0' && *month <= '9'){		tm.mon = atoi(month) - 1;		if(tm.mon < 0 || tm.mon > 11)			tm.mon = 5;	} else {		for(p = month; *p; p++)			*p = tolower(*p);		for(i = 0; i < 12; i++)			if(strncmp(&monthchars[i*3], month, 3) == 0){				tm.mon = i;				break;			}	} 	tm.mday = atoi(day); 	if(hms){		tm.hour = strtol(hms, &p, 0);		if(*p == ':'){			tm.min = strtol(p+1, &p, 0);			if(*p == ':')				tm.sec = strtol(p+1, &p, 0);		}		if(tolower(*p) == 'p')			tm.hour += 12;	} 	if(yr){		tm.year = atoi(yr);		if(tm.year >= 1900)			tm.year -= 1900;	} else {		if(tm.mon > now.mon || (tm.mon == now.mon && tm.mday > now.mday+1))			tm.year--;	} 	/* convert to epoch seconds */	return tm2sec(&tm);} /* *  decode a Unix or Plan 9 file mode */static ulongcrackmode(char *p){	ulong flags;	ulong mode;	int i; 	flags = 0;	switch(strlen(p)){	case 10:	/* unix and new style plan 9 */		switch(*p){		case 'l':			return DMSYML|0777;		case 'd':			flags |= DMDIR;		case 'a':			flags |= DMAPPEND;		}		p++;		if(p[2] == 'l')			flags |= DMEXCL;		break;	case 11:	/* old style plan 9 */		switch(*p++){		case 'd':			flags |= DMDIR;			break;		case 'a':			flags |= DMAPPEND;			break;		}		if(*p++ == 'l')			flags |= DMEXCL;		break;	default:		return DMDIR|0777;	}	mode = 0;	for(i = 0; i < 3; i++){		mode <<= 3;		if(*p++ == 'r')			mode |= DMREAD;		if(*p++ == 'w')			mode |= DMWRITE;		if(*p == 'x' || *p == 's' || *p == 'S')			mode |= DMEXEC;		p++;	}	return mode | flags;} /* *  find first punctuation */char*strpunct(char *p){

Lines 1–500 of 1666.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t