|
@@ -308,7 +308,7 @@ main(int argc, char **argv)
|
|
|
alarm(Maxwait);
|
|
|
}
|
|
|
if(pid)
|
|
|
- postnote(PNGROUP, pid, "kill");
|
|
|
+ postnote(PNPROC, pid, "kill");
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -392,7 +392,8 @@ transfer(char *cmd, char *a1, char *a2, char *a3, int image)
|
|
|
case -1:
|
|
|
return reply("450 Out of processes: %r");
|
|
|
case 0:
|
|
|
-logit("running tar %d\n", getpid());
|
|
|
+ logit("running %s %s %s %s pid %d",
|
|
|
+ cmd, a1?a1:"", a2?a2:"" , a3?a3:"",getpid());
|
|
|
close(pfd[1]);
|
|
|
close(dfd);
|
|
|
dup(pfd[0], 1);
|
|
@@ -454,7 +455,7 @@ logit("running tar %d\n", getpid());
|
|
|
break;
|
|
|
free(w);
|
|
|
}
|
|
|
- if(w != nil && w->msg != nil){
|
|
|
+ if(w != nil && w->msg != nil && w->msg[0] != 0){
|
|
|
bytes = -1;
|
|
|
logit("%s", w->msg);
|
|
|
logit("%s %s %s %s failed %s", cmd, a1?a1:"", a2?a2:"" , a3?a3:"", w->msg);
|
|
@@ -657,7 +658,7 @@ quitcmd(char *arg)
|
|
|
USED(arg);
|
|
|
reply("200 Bye");
|
|
|
if(pid)
|
|
|
- postnote(PNGROUP, pid, "kill");
|
|
|
+ postnote(PNPROC, pid, "kill");
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
@@ -852,8 +853,7 @@ void
|
|
|
listfile(Biobufhdr *b, char *name, int lflag, char *dname)
|
|
|
{
|
|
|
char ts[32];
|
|
|
- char buf[256];
|
|
|
- int n, links;
|
|
|
+ int n, links, pad;
|
|
|
long now;
|
|
|
char *x;
|
|
|
Dir *d;
|
|
@@ -867,8 +867,8 @@ listfile(Biobufhdr *b, char *name, int lflag, char *dname)
|
|
|
if(isnone){
|
|
|
if(strncmp(x, "/incoming/", sizeof("/incoming/")-1) != 0)
|
|
|
d->mode &= ~0222;
|
|
|
- strcpy(d->uid, "none");
|
|
|
- strcpy(d->gid, "none");
|
|
|
+ d->uid = "none";
|
|
|
+ d->gid = "none";
|
|
|
}
|
|
|
|
|
|
strcpy(ts, ctime(d->mtime));
|
|
@@ -884,24 +884,27 @@ listfile(Biobufhdr *b, char *name, int lflag, char *dname)
|
|
|
} else
|
|
|
links = 1;
|
|
|
|
|
|
- n = snprint(buf, sizeof(buf), "%s %3d %-8s %-8s %7lld %s ", mode2asc(d->mode), links,
|
|
|
+ Bprint(b, "%s %3d %-8s %-8s %7lld %s ",
|
|
|
+ mode2asc(d->mode), links,
|
|
|
d->uid, d->gid, d->length, ts+4);
|
|
|
- } else
|
|
|
- n = 0;
|
|
|
- if(dname)
|
|
|
- n += snprint(buf+n, sizeof(buf)-n, "%s/", dname);
|
|
|
- n += snprint(buf+n, sizeof(buf)-n, "%s", name);
|
|
|
- if(Cflag && col + maxnamelen + 1 < 40){
|
|
|
- if(n < maxnamelen+1){
|
|
|
- memset(buf+n, ' ', maxnamelen+1-n);
|
|
|
- buf[maxnamelen+1] = 0;
|
|
|
+ }
|
|
|
+ if(Cflag && maxnamelen < 40){
|
|
|
+ n = strlen(name);
|
|
|
+ pad = ((col+maxnamelen)/(maxnamelen+1))*(maxnamelen+1);
|
|
|
+ if(pad+maxnamelen+1 < 60){
|
|
|
+ Bprint(b, "%*s", pad-col+n, name);
|
|
|
+ col = pad+n;
|
|
|
}
|
|
|
- col += maxnamelen + 1;
|
|
|
- } else {
|
|
|
- n += snprint(buf+n, sizeof(buf)-n, "\r\n");
|
|
|
- col = 0;
|
|
|
+ else{
|
|
|
+ Bprint(b, "\r\n%s", name);
|
|
|
+ col = n;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ if(dname)
|
|
|
+ Bprint(b, "%s/", dname);
|
|
|
+ Bprint(b, "%s\r\n", name);
|
|
|
}
|
|
|
- Bwrite(b, buf, n);
|
|
|
free(d);
|
|
|
}
|
|
|
int
|
|
@@ -923,7 +926,7 @@ void
|
|
|
listdir(char *name, Biobufhdr *b, int lflag, int *printname, Globlist *gl)
|
|
|
{
|
|
|
Dir *p;
|
|
|
- int fd, n, i;
|
|
|
+ int fd, n, i, l;
|
|
|
char *dname;
|
|
|
uvlong total;
|
|
|
|
|
@@ -944,9 +947,11 @@ listdir(char *name, Biobufhdr *b, int lflag, int *printname, Globlist *gl)
|
|
|
n = dirreadall(fd, &p);
|
|
|
close(fd);
|
|
|
if(Cflag){
|
|
|
- for(i = 0; i < n; i++)
|
|
|
- if(strlen(p[i].name) > maxnamelen)
|
|
|
- maxnamelen = strlen(p[i].name);
|
|
|
+ for(i = 0; i < n; i++){
|
|
|
+ l = strlen(p[i].name);
|
|
|
+ if(l > maxnamelen)
|
|
|
+ maxnamelen = l;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* Unix style total line */
|
|
@@ -980,11 +985,10 @@ list(char *arg, int lflag)
|
|
|
int dfd, printname;
|
|
|
int i, n, argc;
|
|
|
char *alist[Narg];
|
|
|
- char path[Maxpath];
|
|
|
char **argv;
|
|
|
Biobufhdr bh;
|
|
|
uchar buf[512];
|
|
|
- char *p;
|
|
|
+ char *p, *s;
|
|
|
|
|
|
if(arg == 0)
|
|
|
arg = "";
|
|
@@ -1035,11 +1039,10 @@ list(char *arg, int lflag)
|
|
|
argv = alist;
|
|
|
argv[0] = ".";
|
|
|
}
|
|
|
+
|
|
|
for(i = 0; i < argc; i++){
|
|
|
chdir(curdir);
|
|
|
- strncpy(path, argv[i], sizeof(path));
|
|
|
- path[sizeof(path)-1] = 0;
|
|
|
- gl = glob(path);
|
|
|
+ gl = glob(argv[i]);
|
|
|
if(gl == nil)
|
|
|
continue;
|
|
|
|
|
@@ -1050,20 +1053,24 @@ list(char *arg, int lflag)
|
|
|
for(g = gl->first; g; g = g->next)
|
|
|
if(g->glob && (n = strlen(s_to_c(g->glob))) > maxnamelen)
|
|
|
maxnamelen = n;
|
|
|
-
|
|
|
- for(g = gl->first; g; g = g->next){
|
|
|
+ while(s = globiter(gl)){
|
|
|
if(debug)
|
|
|
- logit("glob %s", s_to_c(g->glob));
|
|
|
- p = abspath(s_to_c(g->glob));
|
|
|
- if(p == nil)
|
|
|
+ logit("glob %s", s);
|
|
|
+ p = abspath(s);
|
|
|
+ if(p == nil){
|
|
|
+ free(s);
|
|
|
continue;
|
|
|
+ }
|
|
|
d = dirstat(p);
|
|
|
- if(d == nil)
|
|
|
+ if(d == nil){
|
|
|
+ free(s);
|
|
|
continue;
|
|
|
+ }
|
|
|
if(d->qid.type & QTDIR)
|
|
|
- listdir(s_to_c(g->glob), &bh, lflag, &printname, gl);
|
|
|
+ listdir(s, &bh, lflag, &printname, gl);
|
|
|
else
|
|
|
- listfile(&bh, s_to_c(g->glob), lflag, 0);
|
|
|
+ listfile(&bh, s, lflag, 0);
|
|
|
+ free(s);
|
|
|
free(d);
|
|
|
}
|
|
|
globlistfree(gl);
|
|
@@ -1173,28 +1180,29 @@ retrievedir(char *arg)
|
|
|
{
|
|
|
int n;
|
|
|
char *p;
|
|
|
- char file[Maxpath];
|
|
|
+ String *file;
|
|
|
|
|
|
if(type != Timage){
|
|
|
reply("550 This file requires type binary/image");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- strcpy(file, arg);
|
|
|
- p = strrchr(arg, '/');
|
|
|
- if(p != arg){
|
|
|
+ file = s_copy(arg);
|
|
|
+ p = strrchr(s_to_c(file), '/');
|
|
|
+ if(p != s_to_c(file)){
|
|
|
*p++ = 0;
|
|
|
- chdir(arg);
|
|
|
+ chdir(s_to_c(file));
|
|
|
} else {
|
|
|
chdir("/");
|
|
|
- p = arg+1;
|
|
|
+ p = s_to_c(file)+1;
|
|
|
}
|
|
|
|
|
|
n = transfer("/bin/tar", "c", p, 0, 1);
|
|
|
if(n < 0)
|
|
|
- logit("get %s failed", file);
|
|
|
+ logit("get %s failed", arg);
|
|
|
else
|
|
|
- logit("get %s OK %d", file, n);
|
|
|
+ logit("get %s OK %d", arg, n);
|
|
|
+ s_free(file);
|
|
|
}
|
|
|
void
|
|
|
retrieve(char *arg, int arg2)
|
|
@@ -1427,7 +1435,7 @@ storeucmd(char *arg)
|
|
|
USED(arg);
|
|
|
if(isnone)
|
|
|
return reply("550 Permission denied");
|
|
|
- strcpy(name, "ftpXXXXXXXXXXX");
|
|
|
+ strncpy(name, "ftpXXXXXXXXXXX", sizeof name);
|
|
|
mktemp(name);
|
|
|
fd = create(name, OWRITE, createperm);
|
|
|
if(fd == -1)
|
|
@@ -1480,8 +1488,14 @@ int
|
|
|
abortcmd(char *arg)
|
|
|
{
|
|
|
USED(arg);
|
|
|
- if(pid && postnote(PNGROUP, pid, "kill") == 0)
|
|
|
- reply("426 Command aborted");
|
|
|
+
|
|
|
+ logit("abort pid %d", pid);
|
|
|
+ if(pid){
|
|
|
+ if(postnote(PNPROC, pid, "kill") == 0)
|
|
|
+ reply("426 Command aborted");
|
|
|
+ else
|
|
|
+ logit("postnote pid %d %r", pid);
|
|
|
+ }
|
|
|
return reply("226 Abort processed");
|
|
|
}
|
|
|
|
|
@@ -1519,7 +1533,7 @@ helpcmd(char *arg)
|
|
|
/*
|
|
|
* renaming a file takes two commands
|
|
|
*/
|
|
|
-static char filepath[256];
|
|
|
+static String *filepath;
|
|
|
|
|
|
int
|
|
|
rnfrcmd(char *from)
|
|
@@ -1531,16 +1545,20 @@ rnfrcmd(char *from)
|
|
|
from = abspath(from);
|
|
|
if(from == 0)
|
|
|
return reply("550 Permission denied");
|
|
|
- strncpy(filepath, from, sizeof(filepath));
|
|
|
- filepath[sizeof(filepath)-1] = 0;
|
|
|
- return reply("350 Rename %s to ...", filepath);
|
|
|
+ if(filepath == nil)
|
|
|
+ filepath = s_copy(from);
|
|
|
+ else{
|
|
|
+ s_reset(filepath);
|
|
|
+ s_append(filepath, from);
|
|
|
+ }
|
|
|
+ return reply("350 Rename %s to ...", s_to_c(filepath));
|
|
|
}
|
|
|
int
|
|
|
rntocmd(char *to)
|
|
|
{
|
|
|
+ int r;
|
|
|
Dir nd;
|
|
|
- char *fp;
|
|
|
- char *tp;
|
|
|
+ char *fp, *tp;
|
|
|
|
|
|
if(isnone)
|
|
|
return reply("550 Permission denied");
|
|
@@ -1549,24 +1567,26 @@ rntocmd(char *to)
|
|
|
to = abspath(to);
|
|
|
if(to == 0)
|
|
|
return reply("550 Permission denied");
|
|
|
- if(*filepath == 0)
|
|
|
+ if(filepath == nil || *(s_to_c(filepath)) == 0)
|
|
|
return reply("503 Rnto must be preceeded by an rnfr");
|
|
|
|
|
|
tp = strrchr(to, '/');
|
|
|
- fp = strrchr(filepath, '/');
|
|
|
+ fp = strrchr(s_to_c(filepath), '/');
|
|
|
if((tp && fp == 0) || (fp && tp == 0)
|
|
|
- || (fp && tp && (fp-filepath != tp-to || memcmp(filepath, to, tp-to))))
|
|
|
+ || (fp && tp && (fp-s_to_c(filepath) != tp-to || memcmp(s_to_c(filepath), to, tp-to))))
|
|
|
return reply("550 Rename can't change directory");
|
|
|
if(tp)
|
|
|
to = tp+1;
|
|
|
|
|
|
nulldir(&nd);
|
|
|
nd.name = to;
|
|
|
- if(dirwstat(filepath, &nd) < 0)
|
|
|
- return reply("550 Can't rename %s to %s: %r\n", filepath, to);
|
|
|
+ if(dirwstat(s_to_c(filepath), &nd) < 0)
|
|
|
+ r = reply("550 Can't rename %s to %s: %r\n", s_to_c(filepath), to);
|
|
|
+ else
|
|
|
+ r = reply("250 %s now %s", s_to_c(filepath), to);
|
|
|
+ s_reset(filepath);
|
|
|
|
|
|
- filepath[0] = 0;
|
|
|
- return reply("250 %s now %s", filepath, to);
|
|
|
+ return r;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -1605,75 +1625,15 @@ dialdata(void)
|
|
|
return fd;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * to circumscribe the accessible files we have to eliminate ..'s
|
|
|
- * and resolve all names from the root. We also remove any /bin/rc
|
|
|
- * special characters to avoid later problems with executed commands.
|
|
|
- */
|
|
|
-char *special = "`;| ";
|
|
|
-
|
|
|
-char*
|
|
|
-abspath(char *origpath)
|
|
|
-{
|
|
|
- int n, c;
|
|
|
- char *p, *sp, *path;
|
|
|
- char work[Maxpath];
|
|
|
- static char rpath[Maxpath];
|
|
|
-
|
|
|
- if(origpath == 0)
|
|
|
- *work = 0;
|
|
|
- else
|
|
|
- strncpy(work, origpath, sizeof(work));
|
|
|
- path = work;
|
|
|
-
|
|
|
- for(sp = special; *sp; sp++){
|
|
|
- p = strchr(path, *sp);
|
|
|
- if(p)
|
|
|
- *p = 0;
|
|
|
- }
|
|
|
-
|
|
|
- if(*path == '/')
|
|
|
- rpath[0] = 0;
|
|
|
- else
|
|
|
- strcpy(rpath, curdir);
|
|
|
- n = strlen(rpath);
|
|
|
-
|
|
|
- while(*path && n < Maxpath-2){
|
|
|
- p = strchr(path, '/');
|
|
|
- if(p)
|
|
|
- *p++ = 0;
|
|
|
- if(strcmp(path, "..") == 0){
|
|
|
- while(n > 1){
|
|
|
- n--;
|
|
|
- c = rpath[n];
|
|
|
- rpath[n] = 0;
|
|
|
- if(c == '/')
|
|
|
- break;
|
|
|
- }
|
|
|
- } else if(strcmp(path, ".") == 0)
|
|
|
- n = n;
|
|
|
- else if(n == 1)
|
|
|
- n += snprint(rpath+n, Maxpath - n, "%s", path);
|
|
|
- else
|
|
|
- n += snprint(rpath+n, Maxpath - n - 1, "/%s", path);
|
|
|
- if(p)
|
|
|
- path = p;
|
|
|
- else
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if(!accessok(rpath))
|
|
|
- return nil;
|
|
|
-
|
|
|
- return rpath;
|
|
|
-}
|
|
|
-
|
|
|
int
|
|
|
postnote(int group, int pid, char *note)
|
|
|
{
|
|
|
char file[128];
|
|
|
int f, r;
|
|
|
|
|
|
+ /*
|
|
|
+ * Use #p because /proc may not be in the namespace.
|
|
|
+ */
|
|
|
switch(group) {
|
|
|
case PNPROC:
|
|
|
sprint(file, "#p/%d/note", pid);
|
|
@@ -1698,12 +1658,54 @@ postnote(int group, int pid, char *note)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static char *pfile = "/.httplogin";
|
|
|
+/*
|
|
|
+ * to circumscribe the accessible files we have to eliminate ..'s
|
|
|
+ * and resolve all names from the root. We also remove any /bin/rc
|
|
|
+ * special characters to avoid later problems with executed commands.
|
|
|
+ */
|
|
|
+char *special = "`;| ";
|
|
|
+
|
|
|
+char*
|
|
|
+abspath(char *origpath)
|
|
|
+{
|
|
|
+ char *p, *sp, *path;
|
|
|
+ static String *rpath;
|
|
|
+
|
|
|
+ if(rpath == nil)
|
|
|
+ rpath = s_new();
|
|
|
+ else
|
|
|
+ s_reset(rpath);
|
|
|
+
|
|
|
+ if(origpath == nil)
|
|
|
+ s_append(rpath, curdir);
|
|
|
+ else{
|
|
|
+ if(*origpath != '/'){
|
|
|
+ s_append(rpath, curdir);
|
|
|
+ s_append(rpath, "/");
|
|
|
+ }
|
|
|
+ s_append(rpath, origpath);
|
|
|
+ }
|
|
|
+ path = s_to_c(rpath);
|
|
|
+
|
|
|
+ for(sp = special; *sp; sp++){
|
|
|
+ p = strchr(path, *sp);
|
|
|
+ if(p)
|
|
|
+ *p = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ cleanname(s_to_c(rpath));
|
|
|
+ rpath->ptr = rpath->base+strlen(rpath->base);
|
|
|
+
|
|
|
+ if(!accessok(s_to_c(rpath)))
|
|
|
+ return nil;
|
|
|
+
|
|
|
+ return s_to_c(rpath);
|
|
|
+}
|
|
|
|
|
|
typedef struct Path Path;
|
|
|
struct Path {
|
|
|
Path *next;
|
|
|
- char *path;
|
|
|
+ String *path;
|
|
|
int inuse;
|
|
|
int ok;
|
|
|
};
|
|
@@ -1719,32 +1721,33 @@ Path *pathlevel[Maxlevel];
|
|
|
Path*
|
|
|
unlinkpath(char *path, int level)
|
|
|
{
|
|
|
+ String *s;
|
|
|
Path **l, *p;
|
|
|
int n;
|
|
|
|
|
|
n = 0;
|
|
|
for(l = &pathlevel[level]; *l; l = &(*l)->next){
|
|
|
p = *l;
|
|
|
- if(strcmp(p->path, path) == 0){
|
|
|
+ /* hit */
|
|
|
+ if(strcmp(s_to_c(p->path), path) == 0){
|
|
|
*l = p->next;
|
|
|
p->next = nil;
|
|
|
return p;
|
|
|
}
|
|
|
- if(++n >= Maxperlevel - 1 || p->next == nil)
|
|
|
- break;
|
|
|
- }
|
|
|
- if(*l){
|
|
|
/* reuse */
|
|
|
- p = *l;
|
|
|
- *l = p->next;
|
|
|
- free(p->path);
|
|
|
- memset(p, 0, sizeof *p);
|
|
|
-
|
|
|
- } else {
|
|
|
- /* allocate */
|
|
|
- p = mallocz(sizeof *p, 1);
|
|
|
+ if(++n >= Maxperlevel){
|
|
|
+ *l = p->next;
|
|
|
+ s = p->path;
|
|
|
+ s_reset(p->path);
|
|
|
+ memset(p, 0, sizeof *p);
|
|
|
+ p->path = s_append(s, path);
|
|
|
+ return p;
|
|
|
+ }
|
|
|
}
|
|
|
- p->path = strdup(path);
|
|
|
+
|
|
|
+ /* allocate */
|
|
|
+ p = mallocz(sizeof *p, 1);
|
|
|
+ p->path = s_copy(path);
|
|
|
return p;
|
|
|
}
|
|
|
|
|
@@ -1765,11 +1768,12 @@ addpath(Path *p, int level, int ok)
|
|
|
}
|
|
|
|
|
|
int
|
|
|
-_accessok(char *path, int level)
|
|
|
+_accessok(String *s, int level)
|
|
|
{
|
|
|
Path *p;
|
|
|
char *cp;
|
|
|
- int lvl;
|
|
|
+ int lvl, offset;
|
|
|
+ static char httplogin[] = "/.httplogin";
|
|
|
|
|
|
if(level < 0)
|
|
|
return 1;
|
|
@@ -1777,46 +1781,56 @@ _accessok(char *path, int level)
|
|
|
if(lvl >= Maxlevel)
|
|
|
lvl = Maxlevel - 1;
|
|
|
|
|
|
- p = unlinkpath(path, lvl);
|
|
|
+ p = unlinkpath(s_to_c(s), lvl);
|
|
|
if(p->inuse){
|
|
|
/* move to front */
|
|
|
linkpath(p, lvl);
|
|
|
return p->ok;
|
|
|
}
|
|
|
- cp = strrchr(path, '/');
|
|
|
+ cp = strrchr(s_to_c(s), '/');
|
|
|
if(cp == nil)
|
|
|
- cp = path;
|
|
|
- p->path = strdup(path);
|
|
|
- strcat(path, pfile);
|
|
|
- if(access(path, AEXIST) == 0){
|
|
|
+ offset = 0;
|
|
|
+ else
|
|
|
+ offset = cp - s_to_c(s);
|
|
|
+ s_append(s, httplogin);
|
|
|
+ if(access(s_to_c(s), AEXIST) == 0){
|
|
|
addpath(p, lvl, 0);
|
|
|
return 0;
|
|
|
}
|
|
|
- *cp = 0;
|
|
|
- addpath(p, lvl, _accessok(path, level-1));
|
|
|
+
|
|
|
+ /*
|
|
|
+ * There's no way to shorten a String without
|
|
|
+ * knowing the implementation.
|
|
|
+ */
|
|
|
+ s->ptr = s->base+offset;
|
|
|
+ s_terminate(s);
|
|
|
+ addpath(p, lvl, _accessok(s, level-1));
|
|
|
+
|
|
|
return p->ok;
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * work down from the root
|
|
|
+ * check for a subdirectory containing .httplogin
|
|
|
+ * at each level of the path.
|
|
|
*/
|
|
|
int
|
|
|
accessok(char *path)
|
|
|
{
|
|
|
- int level, n;
|
|
|
+ int level, r;
|
|
|
char *p;
|
|
|
- char npath[Maxpath+1];
|
|
|
-
|
|
|
- strcpy(npath, path);
|
|
|
- n = strlen(path)-1;
|
|
|
- if(npath[n] == '/')
|
|
|
- npath[n] = 0;
|
|
|
- p = npath+1;
|
|
|
- for(level = 1; p >= path && level < Maxlevel; level++){
|
|
|
+ String *npath;
|
|
|
+
|
|
|
+ npath = s_copy(path);
|
|
|
+ p = s_to_c(npath)+1;
|
|
|
+ for(level = 1; level < Maxlevel; level++){
|
|
|
p = strchr(p, '/');
|
|
|
if(p == nil)
|
|
|
break;
|
|
|
p++;
|
|
|
}
|
|
|
- return _accessok(npath, level-1);
|
|
|
+
|
|
|
+ r = _accessok(npath, level-1);
|
|
|
+ s_free(npath);
|
|
|
+
|
|
|
+ return r;
|
|
|
}
|