/* * 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. Load more
/* * 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" */ void hello(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 */ void rlogin(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. */ void clogin(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. */ void preamble(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 void ascii(void) { sendrequest("TYPE A", nil); switch(getreply(&ctlin, msg, sizeof(msg), 0)){ case Success: break; default: fatal("can't set type to ascii"); } } static void image(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 ulong cracktime(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 ulong crackmode(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) {