summaryrefslogtreecommitdiffstats
path: root/contrib/lukemftpd/src/cmds.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/lukemftpd/src/cmds.c')
-rw-r--r--contrib/lukemftpd/src/cmds.c973
1 files changed, 0 insertions, 973 deletions
diff --git a/contrib/lukemftpd/src/cmds.c b/contrib/lukemftpd/src/cmds.c
deleted file mode 100644
index 0864110..0000000
--- a/contrib/lukemftpd/src/cmds.c
+++ /dev/null
@@ -1,973 +0,0 @@
-/* $NetBSD: cmds.c,v 1.24 2006/02/01 14:20:12 christos Exp $ */
-
-/*
- * Copyright (c) 1999-2004 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by Luke Mewburn.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * Copyright (C) 1997 and 1998 WIDE Project.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the project nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-
-#include <sys/cdefs.h>
-#ifndef lint
-__RCSID("$NetBSD: cmds.c,v 1.24 2006/02/01 14:20:12 christos Exp $");
-#endif /* not lint */
-
-#include <sys/param.h>
-#include <sys/stat.h>
-
-#include <arpa/ftp.h>
-
-#include <dirent.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <tzfile.h>
-#include <unistd.h>
-#include <ctype.h>
-
-#ifdef KERBEROS5
-#include <krb5/krb5.h>
-#endif
-
-#include "extern.h"
-
-typedef enum {
- FE_MLSD = 1<<0, /* if op is MLSD (MLST otherwise ) */
- FE_ISCURDIR = 1<<1, /* if name is the current directory */
-} factflag_t;
-
-typedef struct {
- const char *path; /* full pathname */
- const char *display; /* name to display */
- struct stat *stat; /* stat of path */
- struct stat *pdirstat; /* stat of path's parent dir */
- factflag_t flags; /* flags */
-} factelem;
-
-static void ack(const char *);
-static void base64_encode(const char *, size_t, char *, int);
-static void fact_type(const char *, FILE *, factelem *);
-static void fact_size(const char *, FILE *, factelem *);
-static void fact_modify(const char *, FILE *, factelem *);
-static void fact_perm(const char *, FILE *, factelem *);
-static void fact_unique(const char *, FILE *, factelem *);
-static int matchgroup(gid_t);
-static void mlsname(FILE *, factelem *);
-static void replydirname(const char *, const char *);
-
-struct ftpfact {
- const char *name; /* name of fact */
- int enabled; /* if fact is enabled */
- void (*display)(const char *, FILE *, factelem *);
- /* function to display fact */
-};
-
-struct ftpfact facttab[] = {
- { "Type", 1, fact_type },
-#define FACT_TYPE 0
- { "Size", 1, fact_size },
- { "Modify", 1, fact_modify },
- { "Perm", 1, fact_perm },
- { "Unique", 1, fact_unique },
- /* "Create" */
- /* "Lang" */
- /* "Media-Type" */
- /* "CharSet" */
-};
-
-#define FACTTABSIZE (sizeof(facttab) / sizeof(struct ftpfact))
-
-static char cached_path[MAXPATHLEN + 1] = "/";
-static void discover_path(char *, const char *);
-
-void
-cwd(const char *path)
-{
-
- if (chdir(path) < 0)
- perror_reply(550, path);
- else {
- show_chdir_messages(250);
- ack("CWD");
- if (getcwd(cached_path, MAXPATHLEN) == NULL) {
- discover_path(cached_path, path);
- }
- }
-}
-
-void
-delete(const char *name)
-{
- char *p = NULL;
-
- if (remove(name) < 0) {
- p = strerror(errno);
- perror_reply(550, name);
- } else
- ack("DELE");
- logxfer("delete", -1, name, NULL, NULL, p);
-}
-
-void
-feat(void)
-{
- int i;
-
- reply(-211, "Features supported");
- cprintf(stdout, " MDTM\r\n");
- cprintf(stdout, " MLST ");
- for (i = 0; i < FACTTABSIZE; i++)
- cprintf(stdout, "%s%s;", facttab[i].name,
- facttab[i].enabled ? "*" : "");
- cprintf(stdout, "\r\n");
- cprintf(stdout, " REST STREAM\r\n");
- cprintf(stdout, " SIZE\r\n");
- cprintf(stdout, " TVFS\r\n");
- reply(211, "End");
-}
-
-void
-makedir(const char *name)
-{
- char *p = NULL;
-
- if (mkdir(name, 0777) < 0) {
- p = strerror(errno);
- perror_reply(550, name);
- } else
- replydirname(name, "directory created.");
- logxfer("mkdir", -1, name, NULL, NULL, p);
-}
-
-void
-mlsd(const char *path)
-{
- struct dirent *dp;
- struct stat sb, pdirstat;
- factelem f;
- FILE *dout;
- DIR *dirp;
- char name[MAXPATHLEN];
- int hastypefact;
-
- hastypefact = facttab[FACT_TYPE].enabled;
- if (path == NULL)
- path = ".";
- if (stat(path, &pdirstat) == -1) {
- mlsdperror:
- perror_reply(550, path);
- return;
- }
- if (! S_ISDIR(pdirstat.st_mode)) {
- errno = ENOTDIR;
- perror_reply(501, path);
- return;
- }
- if ((dirp = opendir(path)) == NULL)
- goto mlsdperror;
-
- dout = dataconn("MLSD", (off_t)-1, "w");
- if (dout == NULL)
- return;
-
- memset(&f, 0, sizeof(f));
- f.stat = &sb;
- f.flags |= FE_MLSD;
- while ((dp = readdir(dirp)) != NULL) {
- snprintf(name, sizeof(name), "%s/%s", path, dp->d_name);
- if (ISDOTDIR(dp->d_name)) { /* special case curdir: */
- if (! hastypefact)
- continue;
- f.pdirstat = NULL; /* require stat of parent */
- f.display = path; /* set name to real name */
- f.flags |= FE_ISCURDIR; /* flag name is curdir */
- } else {
- if (ISDOTDOTDIR(dp->d_name)) {
- if (! hastypefact)
- continue;
- f.pdirstat = NULL;
- } else
- f.pdirstat = &pdirstat; /* cache parent stat */
- f.display = dp->d_name;
- f.flags &= ~FE_ISCURDIR;
- }
- if (stat(name, &sb) == -1)
- continue;
- f.path = name;
- mlsname(dout, &f);
- }
- (void)closedir(dirp);
-
- if (ferror(dout) != 0)
- perror_reply(550, "Data connection");
- else
- reply(226, "MLSD complete.");
- closedataconn(dout);
- total_xfers_out++;
- total_xfers++;
-}
-
-void
-mlst(const char *path)
-{
- struct stat sb;
- factelem f;
-
- if (path == NULL)
- path = ".";
- if (stat(path, &sb) == -1) {
- perror_reply(550, path);
- return;
- }
- reply(-250, "MLST %s", path);
- memset(&f, 0, sizeof(f));
- f.path = path;
- f.display = path;
- f.stat = &sb;
- f.pdirstat = NULL;
- CPUTC(' ', stdout);
- mlsname(stdout, &f);
- reply(250, "End");
-}
-
-
-void
-opts(const char *command)
-{
- struct tab *c;
- char *ep;
-
- if ((ep = strchr(command, ' ')) != NULL)
- *ep++ = '\0';
- c = lookup(cmdtab, command);
- if (c == NULL) {
- reply(502, "Unknown command '%s'.", command);
- return;
- }
- if (! CMD_IMPLEMENTED(c)) {
- reply(502, "%s command not implemented.", c->name);
- return;
- }
- if (! CMD_HAS_OPTIONS(c)) {
- reply(501, "%s command does not support persistent options.",
- c->name);
- return;
- }
-
- /* special case: MLST */
- if (strcasecmp(command, "MLST") == 0) {
- int enabled[FACTTABSIZE];
- int i, onedone;
- size_t len;
- char *p;
-
- for (i = 0; i < sizeof(enabled) / sizeof(int); i++)
- enabled[i] = 0;
- if (ep == NULL || *ep == '\0')
- goto displaymlstopts;
-
- /* don't like spaces, and need trailing ; */
- len = strlen(ep);
- if (strchr(ep, ' ') != NULL || ep[len - 1] != ';') {
- badmlstopt:
- reply(501, "Invalid MLST options");
- return;
- }
- ep[len - 1] = '\0';
- while ((p = strsep(&ep, ";")) != NULL) {
- if (*p == '\0')
- goto badmlstopt;
- for (i = 0; i < FACTTABSIZE; i++)
- if (strcasecmp(p, facttab[i].name) == 0) {
- enabled[i] = 1;
- break;
- }
- }
-
- displaymlstopts:
- for (i = 0; i < FACTTABSIZE; i++)
- facttab[i].enabled = enabled[i];
- cprintf(stdout, "200 MLST OPTS");
- for (i = onedone = 0; i < FACTTABSIZE; i++) {
- if (facttab[i].enabled) {
- cprintf(stdout, "%s%s;", onedone ? "" : " ",
- facttab[i].name);
- onedone++;
- }
- }
- cprintf(stdout, "\r\n");
- fflush(stdout);
- return;
- }
-
- /* default cases */
- if (ep != NULL && *ep != '\0')
- REASSIGN(c->options, ftpd_strdup(ep));
- if (c->options != NULL)
- reply(200, "Options for %s are '%s'.", c->name,
- c->options);
- else
- reply(200, "No options defined for %s.", c->name);
-}
-
-void
-pwd(void)
-{
- char path[MAXPATHLEN];
-
- if (getcwd(path, sizeof(path) - 1) == NULL) {
- if (chdir(cached_path) < 0) {
- reply(550, "Can't get the current directory: %s.",
- strerror(errno));
- return;
- }
- (void)strlcpy(path, cached_path, MAXPATHLEN);
- }
- replydirname(path, "is the current directory.");
-}
-
-void
-removedir(const char *name)
-{
- char *p = NULL;
-
- if (rmdir(name) < 0) {
- p = strerror(errno);
- perror_reply(550, name);
- } else
- ack("RMD");
- logxfer("rmdir", -1, name, NULL, NULL, p);
-}
-
-char *
-renamefrom(const char *name)
-{
- struct stat st;
-
- if (stat(name, &st) < 0) {
- perror_reply(550, name);
- return (NULL);
- }
- reply(350, "File exists, ready for destination name");
- return (ftpd_strdup(name));
-}
-
-void
-renamecmd(const char *from, const char *to)
-{
- char *p = NULL;
-
- if (rename(from, to) < 0) {
- p = strerror(errno);
- perror_reply(550, "rename");
- } else
- ack("RNTO");
- logxfer("rename", -1, from, to, NULL, p);
-}
-
-void
-sizecmd(const char *filename)
-{
- switch (type) {
- case TYPE_L:
- case TYPE_I:
- {
- struct stat stbuf;
- if (stat(filename, &stbuf) < 0 || !S_ISREG(stbuf.st_mode))
- reply(550, "%s: not a plain file.", filename);
- else
- reply(213, ULLF, (ULLT)stbuf.st_size);
- break;
- }
- case TYPE_A:
- {
- FILE *fin;
- int c;
- off_t count;
- struct stat stbuf;
- fin = fopen(filename, "r");
- if (fin == NULL) {
- perror_reply(550, filename);
- return;
- }
- if (fstat(fileno(fin), &stbuf) < 0 || !S_ISREG(stbuf.st_mode)) {
- reply(550, "%s: not a plain file.", filename);
- (void) fclose(fin);
- return;
- }
- if (stbuf.st_size > 10240) {
- reply(550, "%s: file too large for SIZE.", filename);
- (void) fclose(fin);
- return;
- }
-
- count = 0;
- while((c = getc(fin)) != EOF) {
- if (c == '\n') /* will get expanded to \r\n */
- count++;
- count++;
- }
- (void) fclose(fin);
-
- reply(213, LLF, (LLT)count);
- break;
- }
- default:
- reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]);
- }
-}
-
-void
-statfilecmd(const char *filename)
-{
- FILE *fin;
- int c;
- int atstart;
- char *argv[] = { INTERNAL_LS, "-lgA", "", NULL };
-
- argv[2] = (char *)filename;
- fin = ftpd_popen(argv, "r", STDOUT_FILENO);
- reply(-211, "status of %s:", filename);
-/* XXX: use fgetln() or fparseln() here? */
- atstart = 1;
- while ((c = getc(fin)) != EOF) {
- if (c == '\n') {
- if (ferror(stdout)){
- perror_reply(421, "control connection");
- (void) ftpd_pclose(fin);
- dologout(1);
- /* NOTREACHED */
- }
- if (ferror(fin)) {
- perror_reply(551, filename);
- (void) ftpd_pclose(fin);
- return;
- }
- CPUTC('\r', stdout);
- }
- if (atstart && isdigit(c))
- CPUTC(' ', stdout);
- CPUTC(c, stdout);
- atstart = (c == '\n');
- }
- (void) ftpd_pclose(fin);
- reply(211, "End of Status");
-}
-
-/* -- */
-
-static void
-ack(const char *s)
-{
-
- reply(250, "%s command successful.", s);
-}
-
-/*
- * Encode len bytes starting at clear using base64 encoding into encoded,
- * which should be at least ((len + 2) * 4 / 3 + 1) in size.
- * If nulterm is non-zero, terminate with \0 otherwise pad to 3 byte boundary
- * with `='.
- */
-static void
-base64_encode(const char *clear, size_t len, char *encoded, int nulterm)
-{
- static const char base64[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- const char *c;
- char *e, termchar;
- int i;
-
- /* determine whether to pad with '=' or NUL terminate */
- termchar = nulterm ? '\0' : '=';
- c = clear;
- e = encoded;
- /* convert all but last 2 bytes */
- for (i = len; i > 2; i -= 3, c += 3) {
- *e++ = base64[(c[0] >> 2) & 0x3f];
- *e++ = base64[((c[0] << 4) & 0x30) | ((c[1] >> 4) & 0x0f)];
- *e++ = base64[((c[1] << 2) & 0x3c) | ((c[2] >> 6) & 0x03)];
- *e++ = base64[(c[2]) & 0x3f];
- }
- /* handle slop at end */
- if (i > 0) {
- *e++ = base64[(c[0] >> 2) & 0x3f];
- *e++ = base64[((c[0] << 4) & 0x30) |
- (i > 1 ? ((c[1] >> 4) & 0x0f) : 0)];
- *e++ = (i > 1) ? base64[(c[1] << 2) & 0x3c] : termchar;
- *e++ = termchar;
- }
- *e = '\0';
-}
-
-static void
-fact_modify(const char *fact, FILE *fd, factelem *fe)
-{
- struct tm *t;
-
- t = gmtime(&(fe->stat->st_mtime));
- cprintf(fd, "%s=%04d%02d%02d%02d%02d%02d;", fact,
- TM_YEAR_BASE + t->tm_year,
- t->tm_mon+1, t->tm_mday,
- t->tm_hour, t->tm_min, t->tm_sec);
-}
-
-static void
-fact_perm(const char *fact, FILE *fd, factelem *fe)
-{
- int rok, wok, xok, pdirwok;
- struct stat *pdir;
-
- if (fe->stat->st_uid == geteuid()) {
- rok = ((fe->stat->st_mode & S_IRUSR) != 0);
- wok = ((fe->stat->st_mode & S_IWUSR) != 0);
- xok = ((fe->stat->st_mode & S_IXUSR) != 0);
- } else if (matchgroup(fe->stat->st_gid)) {
- rok = ((fe->stat->st_mode & S_IRGRP) != 0);
- wok = ((fe->stat->st_mode & S_IWGRP) != 0);
- xok = ((fe->stat->st_mode & S_IXGRP) != 0);
- } else {
- rok = ((fe->stat->st_mode & S_IROTH) != 0);
- wok = ((fe->stat->st_mode & S_IWOTH) != 0);
- xok = ((fe->stat->st_mode & S_IXOTH) != 0);
- }
-
- cprintf(fd, "%s=", fact);
-
- /*
- * if parent info not provided, look it up, but
- * only if the current class has modify rights,
- * since we only need this info in such a case.
- */
- pdir = fe->pdirstat;
- if (pdir == NULL && CURCLASS_FLAGS_ISSET(modify)) {
- size_t len;
- char realdir[MAXPATHLEN], *p;
- struct stat dir;
-
- len = strlcpy(realdir, fe->path, sizeof(realdir));
- if (len < sizeof(realdir) - 4) {
- if (S_ISDIR(fe->stat->st_mode))
- strlcat(realdir, "/..", sizeof(realdir));
- else {
- /* if has a /, move back to it */
- /* otherwise use '..' */
- if ((p = strrchr(realdir, '/')) != NULL) {
- if (p == realdir)
- p++;
- *p = '\0';
- } else
- strlcpy(realdir, "..", sizeof(realdir));
- }
- if (stat(realdir, &dir) == 0)
- pdir = &dir;
- }
- }
- pdirwok = 0;
- if (pdir != NULL) {
- if (pdir->st_uid == geteuid())
- pdirwok = ((pdir->st_mode & S_IWUSR) != 0);
- else if (matchgroup(pdir->st_gid))
- pdirwok = ((pdir->st_mode & S_IWGRP) != 0);
- else
- pdirwok = ((pdir->st_mode & S_IWOTH) != 0);
- }
-
- /* 'a': can APPE to file */
- if (wok && CURCLASS_FLAGS_ISSET(upload) && S_ISREG(fe->stat->st_mode))
- CPUTC('a', fd);
-
- /* 'c': can create or append to files in directory */
- if (wok && CURCLASS_FLAGS_ISSET(modify) && S_ISDIR(fe->stat->st_mode))
- CPUTC('c', fd);
-
- /* 'd': can delete file or directory */
- if (pdirwok && CURCLASS_FLAGS_ISSET(modify)) {
- int candel;
-
- candel = 1;
- if (S_ISDIR(fe->stat->st_mode)) {
- DIR *dirp;
- struct dirent *dp;
-
- if ((dirp = opendir(fe->display)) == NULL)
- candel = 0;
- else {
- while ((dp = readdir(dirp)) != NULL) {
- if (ISDOTDIR(dp->d_name) ||
- ISDOTDOTDIR(dp->d_name))
- continue;
- candel = 0;
- break;
- }
- closedir(dirp);
- }
- }
- if (candel)
- CPUTC('d', fd);
- }
-
- /* 'e': can enter directory */
- if (xok && S_ISDIR(fe->stat->st_mode))
- CPUTC('e', fd);
-
- /* 'f': can rename file or directory */
- if (pdirwok && CURCLASS_FLAGS_ISSET(modify))
- CPUTC('f', fd);
-
- /* 'l': can list directory */
- if (rok && xok && S_ISDIR(fe->stat->st_mode))
- CPUTC('l', fd);
-
- /* 'm': can create directory */
- if (wok && CURCLASS_FLAGS_ISSET(modify) && S_ISDIR(fe->stat->st_mode))
- CPUTC('m', fd);
-
- /* 'p': can remove files in directory */
- if (wok && CURCLASS_FLAGS_ISSET(modify) && S_ISDIR(fe->stat->st_mode))
- CPUTC('p', fd);
-
- /* 'r': can RETR file */
- if (rok && S_ISREG(fe->stat->st_mode))
- CPUTC('r', fd);
-
- /* 'w': can STOR file */
- if (wok && CURCLASS_FLAGS_ISSET(upload) && S_ISREG(fe->stat->st_mode))
- CPUTC('w', fd);
-
- CPUTC(';', fd);
-}
-
-static void
-fact_size(const char *fact, FILE *fd, factelem *fe)
-{
-
- if (S_ISREG(fe->stat->st_mode))
- cprintf(fd, "%s=" LLF ";", fact, (LLT)fe->stat->st_size);
-}
-
-static void
-fact_type(const char *fact, FILE *fd, factelem *fe)
-{
-
- cprintf(fd, "%s=", fact);
- switch (fe->stat->st_mode & S_IFMT) {
- case S_IFDIR:
- if (fe->flags & FE_MLSD) {
- if ((fe->flags & FE_ISCURDIR) || ISDOTDIR(fe->display))
- cprintf(fd, "cdir");
- else if (ISDOTDOTDIR(fe->display))
- cprintf(fd, "pdir");
- else
- cprintf(fd, "dir");
- } else {
- cprintf(fd, "dir");
- }
- break;
- case S_IFREG:
- cprintf(fd, "file");
- break;
- case S_IFIFO:
- cprintf(fd, "OS.unix=fifo");
- break;
- case S_IFLNK: /* XXX: probably a NO-OP with stat() */
- cprintf(fd, "OS.unix=slink");
- break;
- case S_IFSOCK:
- cprintf(fd, "OS.unix=socket");
- break;
- case S_IFBLK:
- case S_IFCHR:
- cprintf(fd, "OS.unix=%s-%d/%d",
- S_ISBLK(fe->stat->st_mode) ? "blk" : "chr",
- major(fe->stat->st_rdev), minor(fe->stat->st_rdev));
- break;
- default:
- cprintf(fd, "OS.unix=UNKNOWN(0%o)", fe->stat->st_mode & S_IFMT);
- break;
- }
- CPUTC(';', fd);
-}
-
-static void
-fact_unique(const char *fact, FILE *fd, factelem *fe)
-{
- char obuf[(sizeof(dev_t) + sizeof(ino_t) + 2) * 4 / 3 + 2];
- char tbuf[sizeof(dev_t) + sizeof(ino_t)];
-
- memcpy(tbuf,
- (char *)&(fe->stat->st_dev), sizeof(dev_t));
- memcpy(tbuf + sizeof(dev_t),
- (char *)&(fe->stat->st_ino), sizeof(ino_t));
- base64_encode(tbuf, sizeof(dev_t) + sizeof(ino_t), obuf, 1);
- cprintf(fd, "%s=%s;", fact, obuf);
-}
-
-static int
-matchgroup(gid_t gid)
-{
- int i;
-
- for (i = 0; i < gidcount; i++)
- if (gid == gidlist[i])
- return(1);
- return (0);
-}
-
-static void
-mlsname(FILE *fp, factelem *fe)
-{
- char realfile[MAXPATHLEN];
- int i, userf = 0;
-
- for (i = 0; i < FACTTABSIZE; i++) {
- if (facttab[i].enabled)
- (facttab[i].display)(facttab[i].name, fp, fe);
- }
- if ((fe->flags & FE_MLSD) &&
- !(fe->flags & FE_ISCURDIR) && !ISDOTDIR(fe->display)) {
- /* if MLSD and not "." entry, display as-is */
- userf = 0;
- } else {
- /* if MLST, or MLSD and "." entry, realpath(3) it */
- if (realpath(fe->display, realfile) != NULL)
- userf = 1;
- }
- cprintf(fp, " %s\r\n", userf ? realfile : fe->display);
-}
-
-static void
-replydirname(const char *name, const char *message)
-{
- char *p, *ep;
- char npath[MAXPATHLEN * 2];
-
- p = npath;
- ep = &npath[sizeof(npath) - 1];
- while (*name) {
- if (*name == '"') {
- if (ep - p < 2)
- break;
- *p++ = *name++;
- *p++ = '"';
- } else {
- if (ep - p < 1)
- break;
- *p++ = *name++;
- }
- }
- *p = '\0';
- reply(257, "\"%s\" %s", npath, message);
-}
-
-static void
-discover_path(last_path, new_path)
- char *last_path;
- const char *new_path;
-{
- char tp[MAXPATHLEN + 1] = "";
- char tq[MAXPATHLEN + 1] = "";
- char *cp;
- char *cq;
- int sz1, sz2;
- int nomorelink;
- struct stat st1, st2;
-
- if (new_path[0] != '/') {
- (void)strlcpy(tp, last_path, MAXPATHLEN);
- (void)strlcat(tp, "/", MAXPATHLEN);
- }
- (void)strlcat(tp, new_path, MAXPATHLEN);
- (void)strlcat(tp, "/", MAXPATHLEN);
-
- /*
- * resolve symlinks. A symlink may introduce another symlink, so we
- * loop trying to resolve symlinks until we don't find any of them.
- */
- do {
- /* Collapse any // into / */
- while ((cp = strstr(tp, "//")) != NULL)
- (void)memmove(cp, cp + 1, strlen(cp) - 1 + 1);
-
- /* Collapse any /./ into / */
- while ((cp = strstr(tp, "/./")) != NULL)
- (void)memmove(cp, cp + 2, strlen(cp) - 2 + 1);
-
- cp = tp;
- nomorelink = 1;
-
- while ((cp = strstr(++cp, "/")) != NULL) {
- sz1 = (u_long)cp - (u_long)tp;
- if (sz1 > MAXPATHLEN)
- goto bad;
- *cp = 0;
- sz2 = readlink(tp, tq, MAXPATHLEN);
- *cp = '/';
-
- /* If this is not a symlink, move to next / */
- if (sz2 <= 0)
- continue;
-
- /*
- * We found a symlink, so we will have to
- * do one more pass to check there is no
- * more symlink in the path
- */
- nomorelink = 0;
-
- /*
- * Null terminate the string and remove trailing /
- */
- tq[sz2] = 0;
- sz2 = strlen(tq);
- if (tq[sz2 - 1] == '/')
- tq[--sz2] = 0;
-
- /*
- * Is this an absolute link or a relative link?
- */
- if (tq[0] == '/') {
- /* absolute link */
- if (strlen(cp) + sz2 > MAXPATHLEN)
- goto bad;
- memmove(tp + sz2, cp, strlen(cp) + 1);
- memcpy(tp, tq, sz2);
- } else {
- /* relative link */
- for (cq = cp - 1; *cq != '/'; cq--);
- if (strlen(tp) - ((u_long)cq - (u_long)cp)
- + 1 + sz2 > MAXPATHLEN)
- goto bad;
- (void)memmove(cq + 1 + sz2,
- cp, strlen(cp) + 1);
- (void)memcpy(cq + 1, tq, sz2);
- }
-
- /*
- * start over, looking for new symlinks
- */
- break;
- }
- } while (nomorelink == 0);
-
- /* Collapse any /foo/../ into /foo/ */
- while ((cp = strstr(tp, "/../")) != NULL) {
- /* ^/../foo/ becomes ^/foo/ */
- if (cp == tp) {
- (void)memmove(cp, cp + 3,
- strlen(cp) - 3 + 1);
- } else {
- for (cq = cp - 1; *cq != '/'; cq--);
- (void)memmove(cq, cp + 3,
- strlen(cp) - 3 + 1);
- }
- }
-
- /* strip strailing / */
- if (strlen(tp) != 1)
- tp[strlen(tp) - 1] = '\0';
-
- /* check that the path is correct */
- stat(tp, &st1);
- stat(".", &st2);
- if ((st1.st_dev != st2.st_dev) || (st1.st_ino != st2.st_ino))
- goto bad;
-
- (void)strlcpy(last_path, tp, MAXPATHLEN);
- return;
-
-bad:
- (void)strlcat(last_path, "/", MAXPATHLEN);
- (void)strlcat(last_path, new_path, MAXPATHLEN);
- return;
-}
-
OpenPOWER on IntegriCloud