1 /* cmds.c: BetaFTPD command handlers
2 Copyright (C) 1999-2000 Steinar H. Gunderson
4 This program is is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2 if the
6 License as published by the Free Software Foundation.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 #include <sys/types.h>
89 #include <sys/ioctl.h>
93 #include <sys/socket.h>
101 #include <sys/param.h>
109 #include <sys/conf.h>
112 #if HAVE_NETINET_IN_H
113 #include <netinet/in.h>
121 #include <sys/filio.h>
125 #include <sys/poll.h>
150 extern struct conn *first_conn;
152 extern struct dcache *first_dcache;
156 extern struct pollfd fds[];
158 extern fd_set master_fds, master_send_fds;
163 char add_cmlen; /* =1 if the command takes an argument */
164 int (*callback)(struct conn * const);
167 char do_setuid; /* =1 if root is not *really* needed */
171 static const struct handler handler_table[] = {
172 { "user ", 1, cmd_user, 0 NO_SETUID },
173 { "pass ", 1, cmd_pass, 1 NO_SETUID },
174 { "retr ", 1, cmd_retr, 3 DO_SETUID },
175 { "acct ", 1, cmd_acct, 0 NO_SETUID },
176 { "port ", 1, cmd_port, 3 DO_SETUID },
177 { "pasv" , 0, cmd_pasv, 3 DO_SETUID },
178 { "pwd" , 0, cmd_pwd, 3 DO_SETUID },
179 { "cwd " , 1, cmd_cwd, 3 DO_SETUID },
180 { "cdup" , 0, cmd_cdup, 3 DO_SETUID },
181 { "rest ", 1, cmd_rest, 3 DO_SETUID },
182 { "list" , 0, cmd_list, 3 DO_SETUID },
183 { "nlst" , 0, cmd_nlst, 3 DO_SETUID },
184 { "type ", 1, cmd_type, 3 DO_SETUID },
185 { "mode ", 1, cmd_mode, 3 DO_SETUID },
186 { "stru ", 1, cmd_stru, 3 DO_SETUID },
187 { "size ", 1, cmd_size, 3 DO_SETUID },
188 { "mdtm ", 1, cmd_mdtm, 3 DO_SETUID },
189 { "abor" , 0, cmd_abor, 3 DO_SETUID },
190 { "dele ", 1, cmd_dele, 3 DO_SETUID },
191 { "rnfr ", 1, cmd_rnfr, 3 DO_SETUID },
192 { "rnto ", 1, cmd_rnto, 3 DO_SETUID },
193 { "mkd " , 1, cmd_mkd, 3 DO_SETUID },
194 { "rmd " , 1, cmd_rmd, 3 DO_SETUID },
195 { "allo ", 1, cmd_allo, 3 DO_SETUID },
196 { "stat" , 0, cmd_stat, 0 NO_SETUID },
197 { "noop" , 0, cmd_noop, 0 DO_SETUID },
198 { "syst" , 0, cmd_syst, 0 DO_SETUID },
199 { "help" , 0, cmd_help, 0 NO_SETUID },
200 { "quit" , 0, cmd_quit, 0 DO_SETUID },
201 { "rein" , 0, cmd_rein, 0 DO_SETUID },
203 /* deprecated forms */
204 { "xcup" , 0, cmd_cdup, 3 DO_SETUID },
205 { "xcwd ", 1, cmd_cwd, 3 DO_SETUID },
206 { "xpwd" , 0, cmd_pwd, 3 DO_SETUID },
207 { "xmkd ", 1, cmd_mkd, 3 DO_SETUID },
208 { "xrmd ", 1, cmd_rmd, 3 DO_SETUID },
210 { "stor ", 1, cmd_stor, 3 DO_SETUID },
211 { "appe ", 1, cmd_appe, 3 DO_SETUID },
214 #warning Use DOING_PROFILING with caution, and NEVER on a production server! :-)
215 { "exit", 0, cmd_exit, 0 NO_SETUID },
217 { "" , 0, NULL, 0 NO_SETUID }
221 * do_chdir(): Does a chdir() to newd on c, staying inside the
222 * limits of root_dir. Use this instead of a chdir() whenever
223 * you can, and possibly even when you can't :-)
225 * This command quirks around some problems in the rest of
226 * the code (namely translate_path()), so a blank newdir is
227 * interpreted as the root directory.
229 int do_chdir(struct conn * const c, const char * const newd)
231 char chd[512], temp[512];
233 TRAP_ERROR(chdir(c->curr_dir) == -1, 550, return -1);
235 /* handle `absolute' paths */
236 if (newd[0] == '/' || newd[0] == '\0') {
237 strcpy(temp, c->root_dir);
240 * is this the root directory? if not, remove the trailing `/'
241 * and concatenate the new directory on
243 if (newd[1] != '\0' && newd[0] != '\0') {
244 temp[strlen(temp) - 1] = 0;
252 if (nr_check_permission(c->uid, temp, 1, 1, NULL) == -1) {
253 numeric(c, 550, "Permission denied");
258 TRAP_ERROR(chdir(temp) == -1, 550, return -1);
261 if (chd[strlen(chd) - 1] != '/') {
265 if (strncmp(chd, c->root_dir, strlen(c->root_dir)) != 0) {
266 numeric(c, 550, "No such file or directory.");
274 * cmd_user(): Handles the USER command, and does most of the initial
275 * authentication work. User names are limited to 16
276 * characters, by force...
278 int cmd_user(struct conn * const c)
280 strncpy(c->username, c->recv_buf, 16);
283 if (strcasecmp(c->username, "anonymous") == 0) {
284 strcpy(c->username, "ftp");
286 if (strcasecmp(c->username, "ftp") == 0) {
287 numeric(c, 331, "Login OK, send password (your e-mail).");
290 numeric(c, 331, "Password required for %s.", c->username);
297 * cmd_pass(): Handles the PASS command, and checks the password.
298 * This function is rather long and complicated, mostly
299 * because there are so many ways of doing users
300 * (including my nonroot system) out there... And we
301 * don't even support PAM or real shadow passwords (with
304 int cmd_pass(struct conn * const c)
307 c->auth = nr_userinfo(c->username, &c->uid, c->curr_dir, c->root_dir,
309 #else /* !WANT_NONROOT */
310 #if WANT_SHADOW && HAVE_SHADOW_H
315 p = getpwnam(c->username);
316 #if WANT_SHADOW && HAVE_SHADOW_H
317 s = getspnam(c->username);
324 strncpy(c->curr_dir, p->pw_dir, 254);
325 c->curr_dir[254] = 0;
329 if (c->curr_dir[strlen(c->curr_dir) - 1] != '/') {
330 strcat(c->curr_dir, "/");
332 strcpy(c->root_dir, c->curr_dir);
334 } else if (c->auth != 0) {
335 strcpy(c->root_dir, "/");
336 if (strcmp(crypt(c->recv_buf, p->pw_passwd), p->pw_passwd) != 0
337 #if WANT_SHADOW && HAVE_SHADOW_H
338 && (s == NULL || strcmp(crypt(c->recv_buf, s->sp_pwdp), s->sp_pwdp) != 0)
346 #endif /* !WANT_NONROOT */
348 /* root should not be allowed to FTP */
353 numeric(c, 530, "Login incorrect.");
357 dump_file(c, 230, "welcome.msg");
359 numeric(c, 230, "User logged in.");
365 * cmd_acct(): Handle (ignore) the ACCT command. I don't see how we
366 * could make use of this command... wu-ftpd doesn't, either.
367 * However, wu-ftpd (at least the version I have here) uses
368 * 502, which isn't a legal error code according to RFC959.
369 * 202, on the other hand, is, and seems to be applicable.
371 * I'm unsure if this one should require setuid or not, but
372 * I feel that the RFC959 intention is having it _before_
373 * USER/PASS. Therefore, this one runs with root privilegies :-)
375 int cmd_acct(struct conn * const c)
377 numeric(c, 202, "ACCT ignored OK -- not applicable on this system.");
382 * cmd_port(): Handles the PORT command, and sets up the data socket.
383 * Making a brief uid=0 (root) appearance (to bind the socket) --
384 * I feel it's safer that way (instead of running as root
385 * the whole way), in case there are some weird overflows
388 int cmd_port(struct conn * const c)
390 short int a0, a1, a2, a3, p0, p1;
393 struct sockaddr_in sin;
395 if ((c->transfer != NULL) && (c->transfer->state >= 4)) {
396 numeric(c, 500, "Sorry, only one transfer at a time.");
400 sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
401 TRAP_ERROR(sock == -1, 500, return 1);
403 destroy_ftran(c->transfer);
404 c->transfer = f = alloc_new_ftran(sock, c);
406 i = sscanf(c->recv_buf, "%3hu,%3hu,%3hu,%3hu,%3hu,%3hu", &a0, &a1, &a2, &a3, &p0, &p1);
408 numeric(c, 501, "Parse error.");
413 /* bind to own address, port 20 (FTP data) */
415 err = getsockname(c->sock, (struct sockaddr *)&sin, &tmp);
416 TRAP_ERROR(err == -1, 500, return 1);
417 sin.sin_port = FTP_PORT - 1;
419 numeric(c, 200, "PORT command OK.");
421 /* note that bind() might well fail, so we don't error check */
423 /* need root privilegies for a short while */
426 bind(sock, (struct sockaddr *)&sin, sizeof(sin));
431 f->sin.sin_family = AF_INET;
432 f->sin.sin_addr.s_addr = htonl(
433 ((unsigned char)(a0) << 24) +
434 ((unsigned char)(a1) << 16) +
435 ((unsigned char)(a2) << 8) +
436 ((unsigned char)(a3) ));
437 f->sin.sin_port = htons(
438 ((unsigned char)(p0) << 8) +
439 ((unsigned char)(p1) ));
444 ioctl(f->sock, FIONBIO, &one);
450 * cmd_pasv(): Handles the PASV command, and sets up the data socket.
451 * Uses port numbers > 1024, since it doesn't run as root.
453 int cmd_pasv(struct conn * const c)
457 unsigned int one = 1;
458 struct sockaddr_in addr;
460 if ((c->transfer != NULL) && (c->transfer->state >= 4)) {
461 numeric(c, 503, "Sorry, only one transfer at once.");
464 destroy_ftran(c->transfer);
466 sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
467 TRAP_ERROR(sock == -1, 500, return 1);
468 err = add_fd(sock, POLLIN);
469 TRAP_ERROR(err != 0, 501, return 1);
471 c->transfer = f = alloc_new_ftran(sock, c);
473 ioctl(sock, FIONBIO, &one);
477 err = getsockname(c->sock, (struct sockaddr *)&addr, &tmp);
478 TRAP_ERROR(err == -1, 500, return 1);
480 addr.sin_port = 0; /* let the system choose */
481 err = bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr));
482 TRAP_ERROR(err == -1, 500, return 1);
485 err = getsockname(sock, (struct sockaddr *)&addr, &tmp);
486 TRAP_ERROR(err == -1, 500, return 1);
488 err = listen(f->sock, 1);
489 TRAP_ERROR(err == -1, 500, return 1);
492 numeric(c, 227, "Entering passive mode (%u,%u,%u,%u,%u,%u)",
493 (htonl(addr.sin_addr.s_addr) & 0xff000000) >> 24,
494 (htonl(addr.sin_addr.s_addr) & 0x00ff0000) >> 16,
495 (htonl(addr.sin_addr.s_addr) & 0x0000ff00) >> 8,
496 (htonl(addr.sin_addr.s_addr) & 0x000000ff),
497 (htons(addr.sin_port) & 0xff00) >> 8,
498 (htons(addr.sin_port) & 0x00ff));
503 * cmd_pwd(): Handles PWD command (print working directory).
505 * Note that if somebody contacts you with the message `the server
506 * says curr_dir() is outside root_dir()', you should fix your
507 * /betaftpd.users file, if you use nonroot. If not, it's a bug.
508 * Try to get it _reproducible_, and mail it to me.
510 int cmd_pwd(struct conn * const c)
512 char temp[512], *cdir = NULL;
514 cdir = do_pwd(c, temp, c->curr_dir);
516 numeric(c, 257, "\"%s\" is current working directory.", cdir);
522 * do_pwd(): Translates an absolute path to a path suitable for viewing
523 * to the user (ie. removes the root_dir, and removes a trailing
524 * slash if it exists). Note that the retbuf is only used as a
525 * storage place -- the pointer to the right place within retbuf
528 char *do_pwd(struct conn * const c, char * const retbuf, const char * const dir)
533 if (strncmp(retbuf, c->root_dir, strlen(c->root_dir)) != 0) {
534 numeric(c, 550, "curr_dir is outside root_dir, please contact site administrator.");
538 cdir = retbuf + strlen(c->root_dir) - 1;
539 if (cdir[strlen(cdir) - 1] == '/' && strlen(cdir) > 1) {
540 cdir[strlen(cdir) - 1] = 0;
541 } else if (strlen(cdir) == 0) {
549 * cmd_cwd(): Handles CWD command (change working directory). Uses
550 * cmd_cwd_internal() (see below).
552 int cmd_cwd(struct conn * const c)
554 cmd_cwd_internal(c, c->recv_buf);
559 * cmd_cdup(): Handles a CDUP command (identical to `CWD ..'). Note that
560 * RFC959 gives two different response codes (250 and 200) --
561 * 250 is the same as CWD gives, which sounds logical to me.
562 * wu-ftpd uses it as well.
564 * Note that using a CDUP to try to get outside root_dir returns
565 * an error, instead of just staying in the root directory (as
566 * the OS and thus wu-ftpd does).
568 int cmd_cdup(struct conn * const c)
570 cmd_cwd_internal(c, "..");
575 * cmd_cwd_internal():
576 * Does the work for CWD and CDUP (modularized to save some
577 * space and have clearer code). Mostly, it just uses do_chdir(),
578 * and sees where that takes us. It adds a trailing slash if needed.
580 void cmd_cwd_internal(struct conn * const c, const char * const newd)
582 if (do_chdir(c, newd) != -1) {
585 getcwd(c->curr_dir, 254);
586 i = strlen(c->curr_dir);
587 if (c->curr_dir[i - 1] != '/') {
588 c->curr_dir[i++] = '/';
589 c->curr_dir[i] = '\0';
593 dump_file(c, 250, ".message");
597 numeric(c, 250, "CWD successful.");
602 * cmd_rest(): Handles the REST command. All it does is tell the file
603 * sending functions to start at the correct number. We should
604 * perhaps add some better error checking to this?
606 int cmd_rest(struct conn * const c)
608 c->rest_pos = abs(atoi(c->recv_buf));
609 numeric(c, 350, "Setting resume at %u bytes.", c->rest_pos);
614 * cmd_retr(): Handles the RETR command. This command doesn't send the
615 * file, but it opens it and tells the socket handling code
616 * to check for activity on the data socket. When the
617 * connection occurs (or succeeds, if we're using PORT mode),
618 * the actual file transfer begins.
620 int cmd_retr(struct conn * const c)
622 struct ftran *f = c->transfer;
624 if ((f == NULL) || ((f->state != 1) && (f->state != 3))) {
625 numeric(c, 425, "No data connection set up; please use PASV or PORT.");
630 if ((c->rest_pos > 0) && (c->ascii_mode == 1)) {
631 numeric(c, 500, "Cannot resume while in ASCII mode.");
636 f->local_file = do_openfile(c, c->recv_buf, f->filename, O_RDONLY
643 if (f->local_file == -1) {
644 numeric(f->owner, 550, strerror(errno));
646 } else if (f->local_file == -2) {
653 prepare_for_transfer(f);
660 * cmd_stor(): Handles the STOR command (upload file). Pushes the
661 * work down to do_store(), below.
663 int cmd_stor(struct conn * const c)
670 * cmd_appe(): Handles the APPE command (append to file). Pushes
671 * the work down to do_store(), below.
673 int cmd_appe(struct conn * const c)
680 * do_store(): Initiate an upload. Most of the comments to do_retr()
681 * (above) apply to this one as well.
683 void do_store(struct conn * const c, const int append)
685 struct ftran *f = c->transfer;
687 if ((f == NULL) || ((f->state != 1) && (f->state != 3))) {
688 numeric(c, 425, "No data connection set up; please use PASV or PORT.");
693 if ((c->rest_pos > 0) && (c->ascii_mode == 1)) {
694 numeric(c, 500, "Cannot resume while in ASCII mode.");
699 f->local_file = do_openfile(c, c->recv_buf, f->filename, O_WRONLY |
700 O_CREAT | ((append || c->rest_pos > 0) ? 0 : O_TRUNC)
707 if (f->local_file == -1) {
708 numeric(f->owner, 550, strerror(errno));
709 } else if (f->local_file == -2) {
715 f->ascii_mode = c->ascii_mode;
717 prepare_for_transfer(f);
720 #endif /* WANT_UPLOAD */
723 * cmd_size(): Handle the SIZE command -- returns the size of a
724 * file. Note that this command is not part of RFC959,
725 * and thus there is no clear specification (except
726 * for some ftpext documents, which we try to follow
727 * as closely as we can). BetaFTPD deviates from wu-ftpd
728 * in that it lets you check the `size' of directories
729 * as well (instead of giving 550). This is _not_ the
730 * size of all the files in the directory, rather how
731 * much space the directory inode uses.
733 int cmd_size(struct conn * const c)
737 numeric(c, 550, "SIZE not available in ASCII mode.");
742 const char * const fname = translate_path(c, c->recv_buf);
745 TRAP_ERROR(fname == NULL || lstat(fname, &buf) == -1, 550, return 1);
747 numeric(c, 213, "%lu", (unsigned long)(buf.st_size));
753 * cmd_mdtm(): Handle the MDTM command -- returns the modification
754 * date/time of a file. See the comments on cmd_size(),
757 int cmd_mdtm(struct conn * const c)
759 const char * const fname = translate_path(c, c->recv_buf);
763 TRAP_ERROR(fname == NULL || lstat(fname, &buf) == -1, 550, return 1);
765 m = gmtime(&(buf.st_mtime)); /* at least wu-ftpd does it in GMT */
766 numeric(c, 213, "%u%02u%02u%02u%02u%02u", m->tm_year + 1900,
767 m->tm_mon + 1, m->tm_mday, m->tm_hour, m->tm_min, m->tm_sec);
772 * cmd_abor(): Handle the ABOR command (abort a file transfer). This should
773 * be clean enough, but isn't tested extensively.
775 int cmd_abor(struct conn * const c)
777 if (c->transfer != NULL) {
778 numeric(c, 426, "File transfer aborted.");
779 destroy_ftran(c->transfer);
781 numeric(c, 226, "ABOR command processed OK.");
786 * cmd_dele(): Handle the DELE command (delete a file).
788 int cmd_dele(struct conn * const c)
790 const char * const fname = translate_path(c, c->recv_buf);
792 TRAP_ERROR(fname == NULL || unlink(fname) == -1, 550, return 1);
793 numeric(c, 250, "File deleted OK.");
798 * cmd_rnfr(): Handle the RNFR command (take a filename to rename from).
800 int cmd_rnfr(struct conn * const c)
802 const char * const fname = translate_path(c, c->recv_buf);
806 c->rename_from[0] = '\0';
807 if (fname == NULL) return 1;
810 snprintf(c->rename_from, 256, "%s/%s", cwd, fname);
812 /* Just check that the file exists. */
813 TRAP_ERROR(lstat(c->rename_from, &buf) == -1, 550, c->rename_from[0] = '\0'; return 1);
815 numeric(c, 350, "File exists, send RNTO.");
820 * cmd_rnto(): Handle the RNTO command (do the actual renaming).
822 int cmd_rnto(struct conn * const c)
824 const char * const fname = translate_path(c, c->recv_buf);
826 if (fname == NULL) return 1;
827 if (c->rename_from[0] == '\0') {
828 numeric(c, 503, "Please send RNFR first.");
832 TRAP_ERROR(rename(c->rename_from, fname) == -1, 550, c->rename_from[0] = '\0'; return 1);
833 c->rename_from[0] = '\0';
835 numeric(c, 250, "File renamed successfully.");
840 * cmd_mkd(): Handle the MKD/XMKD command (create a new directory).
841 * RFC959 is not clear on the error codes for this command --
842 * one place, 521 is cited as the correct error, but is
843 * mentioned nowhere else. Different FTP servers differ here
844 * as well. Thus, I've followed what appears to be the intention
845 * (having `analogous' errors with STOR), and use 550 instead.
847 * Making directories is probably the topic covered most
848 * extensively by RFC959 (and in the most confusing way as
849 * well). I try to follow the conventions, but it isn't always
850 * easy :-) (This code isn't quite easy to understand, because
851 * temp2 is used twice, in two different roles.)
853 int cmd_mkd(struct conn * const c)
855 const char * const fname = translate_path(c, c->recv_buf);
856 char temp[512], temp2[1024], *cdir;
859 TRAP_ERROR(fname == NULL || mkdir(fname, 0755) == -1, 550, return 1);
863 cdir = do_pwd(c, temp, temp2);
865 /* double the quotes in the output */
866 for (i = 0, j = 0; i <= strlen(cdir); i++, j++) {
868 if (cdir[i] == '"') {
872 numeric(c, 257, "\"%s\" created.", temp2);
877 * cmd_rmd(): Handle the RMD/XRMD command. Works just like DELE, only for
880 int cmd_rmd(struct conn * const c)
882 const char * const fname = translate_path(c, c->recv_buf);
884 TRAP_ERROR(fname == NULL || rmdir(fname) == -1, 550, return 1);
885 numeric(c, 250, "Directory deleted.");
890 * cmd_allo(): Handle the ALLO command. The command does not do anything, except
891 * sit around and play compliant. Some Windows FTP servers (Serv-U,
892 * for instance), verifies that there is enough space on the disk,
893 * but since we have no idea on what the filesystem will be stored on,
894 * we just ignore the command.
896 * We could theoretically use this information to give more information
897 * to the full-screen mode, but close to no FTP clients send this
898 * command, and it would touch too much code.
900 int cmd_allo(struct conn * const c)
902 numeric(c, 202, "No storage allocation necessary.");
907 * cmd_stat(): Handle the STAT command. Please see README for more details.
908 * Note that this command is run with euid=root, since it has
909 * to be able to run before USER.
911 * Note that we need to bypass numeric(), to get a multi-line
915 char conn_state[5][27] = {
917 "Waiting for e-mail address",
918 "Waiting for password",
920 "Waiting for password", /* actually non-existant user */
923 char ftran_state[6][42] = {
925 "Decided PASV address/port",
926 "Waiting on PASV socket",
927 "Got PORT address/port",
928 "Connecting on PORT address/port",
929 "Transferring file (or connecting on PORT)"
933 int cmd_stat(struct conn * const c)
938 struct ftran *f = c->transfer;
940 snprintf(buf, 1024, "211- FTP server status:\r\n"
941 " BetaFTPD version " VERSION " (http://members.xoom.com/sneeze/betaftpd.html)\r\n"
942 " Connected to %s\r\n"
943 " Control connection state: %s\r\n"
945 " TYPE: %s; STRUcture: File; transfer MODE: Stream\r\n"
947 " TYPE: Image; STRUcture: File; transfer MODE: Stream\r\n"
949 " Data connection state: %s\r\n"
950 "211 End of status\r\n",
951 inet_ntoa(((struct sockaddr_in *)(&(c->addr)))->sin_addr),
954 (c->ascii_mode == 1) ? "ASCII, FORM: Nonprint" : "Image",
956 (f) ? ftran_state[f->state] : ftran_state[0]);
960 err = send(c->sock, buf, i, 0);
961 if (err == -1 && errno == EPIPE) {
966 numeric(c, 502, "STAT command disabled for security reasons.");
973 * _mwrite(): This define is for mmap-listing. It works as a write()
974 * (not in parameter, but in function), and is used in
975 * cmd_list() and cmd_nlst() only.
977 * Note that this function returns the new position in the
978 * `file'. The caller is expected to send this information
979 * back in `pos' at the next call to _mwrite().
981 int _mwrite(const char * const buf, const struct ftran * const f,
982 const int pos, const int count, const int size)
984 if (pos + count >= size) return size; /* out of space */
985 memcpy(f->file_data + pos, buf, count);
991 * mwrite: This is a short_hand define, making calls to _mwrite() very
992 * similiar to calls to write(). It works both with and without
996 #define mwrite(buf, count) pos = _mwrite((buf), (f), (pos), (count), (size));
998 #define mwrite(buf, count) write(f->local_file, buf, count);
1003 * Formats output in `ls -l' style. It returns one line for the
1004 * file PATHNAME, and returns it in retbuf. Setting do_classify
1005 * to nonzero has the same effect as `ls -F'.
1007 * This command is so long, because simply there is so much to
1008 * be done. GNU ls has some extra functions, but it's close to
1011 int long_listing(char * const retbuf, const char * const pathname, const int do_classify)
1014 char newd[512], temp[1026];
1018 char username[17], groupname[17];
1021 year = localtime(&now)->tm_year;
1028 if (lstat(pathname, &buf) == -1) return 0;
1031 strcpy(username, nr_get_uname(buf.st_uid));
1032 strcpy(groupname, nr_get_gname(buf.st_gid));
1034 p = getpwuid(buf.st_uid);
1036 strncpy(username, p->pw_name, 16);
1039 snprintf(username, 16, "%u", buf.st_uid);
1042 g = getgrgid(buf.st_gid);
1044 strncpy(groupname, g->gr_name, 16);
1047 snprintf(groupname, 16, "%u", buf.st_gid);
1053 * This POSIX approximation is based on GNU ls code (and obfuscated
1054 * a bit...), to be compatible with `real' ls implementations.
1056 t = localtime(&(buf.st_mtime));
1057 strftime(newd, 512, ((now > buf.st_mtime + 6L * 30L * 24L * 60L * 60L) ||
1058 (now < buf.st_mtime - 60L * 60L))
1059 ? "%b %e %Y" : "%b %e %H:%M", t);
1065 if (nr_check_permission(0, pathname, 0, (S_ISDIR(buf.st_mode)), rights) == -1) {
1066 /* no permission to even see this file */
1070 snprintf(temp, 1024, "%c%s %3u %-8s %-8s %8lu %12s %s\r\n",
1072 snprintf(temp, 1024, "%c%c%c%c%c%c%c%c%c%c %3u %-8s %-8s %8lu %12s %s",
1074 decode_mode(buf.st_mode),
1078 (buf.st_mode & S_IRUSR) ? 'r' : '-',
1079 (buf.st_mode & S_IWUSR) ? 'w' : '-',
1080 (buf.st_mode & S_IXUSR) ? ((buf.st_mode & S_ISUID) ? 's' : 'x') : '-',
1081 (buf.st_mode & S_IRGRP) ? 'r' : '-',
1082 (buf.st_mode & S_IWGRP) ? 'w' : '-',
1083 (buf.st_mode & S_IXGRP) ? ((buf.st_mode & S_ISGID) ? 's' : 'x') : '-',
1084 (buf.st_mode & S_IROTH) ? 'r' : '-',
1085 (buf.st_mode & S_IWOTH) ? 'w' : '-',
1086 (buf.st_mode & S_IXOTH) ? ((buf.st_mode & S_ISVTX) ? 't' : 'x') : '-',
1088 buf.st_nlink, username, groupname,
1089 (unsigned long)(buf.st_size), newd, pathname);
1094 * vim needs this extra character for some reason... It's too
1095 * bad I'll have to do it this way, but syntax colouring
1096 * that works properly is almost a `must' for me :-)
1101 /* add an extra classification `sign' if we got -F */
1103 int len = strlen(temp);
1104 temp[len] = classify(buf.st_mode);
1105 temp[len + 1] = '\0';
1109 strcpy(retbuf, temp);
1114 * cmd_list(): Handles the LIST command (directory listing). Does a
1115 * long listing (of type `ls -l'). The listing work is
1116 * done by do_listing(), below.
1118 int cmd_list(struct conn * const c)
1120 struct list_options lo;
1123 lo.long_listing = 1;
1131 * cmd_nlst(): Handles the NLST command (plain directory listing).
1132 * Does a plain listing (no dates etc.), unless overridden
1133 * by the `-l' or `-L' flag (case insensitivity because most
1134 * FTP clients don't have a clue about what they send out).
1135 * The listing work is done by do_listing(), below.
1137 int cmd_nlst(struct conn * const c)
1139 struct list_options lo;
1142 lo.long_listing = 0;
1151 * Prepares any listing buffers, temp files, etc., before
1152 * pushing the work one step further :-)
1154 * If the directory listing cache is enabled, the cache
1155 * is checked first, to see if we still have a valid entry.
1157 void do_listing(struct conn * const c, struct list_options * const lo)
1164 struct ftran * const f = c->transfer;
1171 #warning No nonroot checking for list_core() yet
1174 i = prepare_for_listing(c, &ptr, lo);
1176 destroy_ftran(c->transfer);
1185 strcpy(f->filename, "(directory listing)");
1190 struct dcache *d = NULL, *next = first_dcache->next_dcache;
1193 if (stat(cwd, &buf) > -1) {
1194 /* run through the linked list */
1195 while (next != NULL) {
1197 next = d->next_dcache;
1199 if (buf.st_mtime <= d->generated &&
1200 strcmp(d->dir_name, cwd) == 0 &&
1201 strcmp(d->pattern, ptr) == 0 &&
1202 memcmp(&(d->lo), lo,
1203 sizeof(struct list_options)) == 0) {
1206 f->file_data = d->dir_data;
1207 f->size = d->dir_size;
1210 prepare_for_transfer(f);
1220 int num_files = get_num_files(c, ptr, lo);
1221 if (num_files == -1) return;
1223 size = num_files * 160;
1224 f->file_data = malloc(size + 1);
1225 TRAP_ERROR(f->file_data == NULL, 550, return);
1226 list_core(c, ptr, "", lo, size, 0);
1229 list_core(c, ptr, "", lo);
1233 populate_dcache(f, cwd, ptr, lo);
1239 prepare_for_transfer(f);
1244 * Get the number of files in PATHNAME (optionally matching
1245 * a pattern). Note that c is needed for TRAP_ERROR.
1247 int get_num_files(struct conn * const c, const char * const pathname,
1248 struct list_options * const lo)
1254 * glob() fails to set errno correctly, so we simply guess on
1255 * `permission denied'... The others are far less likely to happen.
1257 switch (glob(pathname, 0, NULL, &pglob)) {
1263 num_files = pglob.gl_pathc;
1266 numeric(c, 550, strerror(EACCES));
1270 if (lo->recursive) {
1272 for (i = 0; i < pglob.gl_pathc; i++) {
1273 char *temp = pglob.gl_pathv[i];
1277 if (S_ISDIR(buf.st_mode)) {
1279 num_files += get_num_files(c, "*", lo);
1291 * list_core(): Enumerate all the files in PATHNAME, and formats them
1292 * according to list_options (calling format functions if
1295 * Note that we don't do any realloc() yet, so if your
1296 * _average_ file name length is over a certain size (a little
1297 * under 80 for long listings, and a little under 160 for
1298 * short listings), the list will be truncated. Fix...
1300 * The return value only makes sense if mmap()'ing, since it
1301 * returns the number of bytes written into the buffer.
1303 * This function is rather long.
1305 int list_core(struct conn * const c, const char * const pathname,
1306 char * const disp_pathname, struct list_options * const lo
1308 , const int size, int pos
1314 struct ftran * const f = c->transfer;
1317 * glob() fails to set errno correctly, so we simply guess on
1318 * `permission denied'... The others are far less likely to happen.
1320 switch (glob(pathname, GLOB_MARK, NULL, &pglob)) {
1325 break; /* note: break, not return */
1327 numeric(c, 550, strerror(EACCES));
1335 if (lo->recursive) {
1336 if (disp_pathname[0] == '\0') {
1337 mwrite(".:\r\n", 4);
1342 snprintf(temp, 1024, "%s:\r\n", disp_pathname);
1347 if (lo->long_listing) {
1348 /* FIX: we may get too high total number if we are running nonroot! */
1350 long unsigned int total = 0;
1353 for (i = 0; i < pglob.gl_pathc; i++) {
1354 if (lstat(pglob.gl_pathv[i], &buf) != -1) {
1355 total += buf.st_blocks;
1358 snprintf(temp, 1024, "total %lu\r\n", total >> 1);
1363 for (i = 0; i < pglob.gl_pathc; i++) {
1364 char * const temp = pglob.gl_pathv[i];
1367 /* strip `/' away from the pathname -- add it later if -F */
1369 int len = strlen(temp);
1370 if (temp[len - 1] == '/') {
1371 temp[len - 1] = '\0';
1375 if (lo->long_listing) {
1376 if (long_listing(buf, temp, lo->classify) == 0) continue;
1380 struct stat statbuf;
1382 if (lstat(buf, &statbuf) != -1) {
1383 const int len = strlen(buf);
1385 buf[len] = classify(statbuf.st_mode);
1391 mwrite(buf, strlen(buf));
1396 * If recursion is on, dive into any subdirectories now -- note
1397 * that each entry is stat()'ed twice, hopefully the OS will manage,
1398 * and we've got our own dcache anyways -- this could be fixed at
1399 * the expense of some memory, consider for later inclusion.
1401 if (lo->recursive) {
1402 for (i = 0; i < pglob.gl_pathc; i++) {
1404 const char * const temp = pglob.gl_pathv[i];
1406 /* don't dive into `.' or `..' */
1407 if (lstat(temp, &buf) != -1 && S_ISDIR(buf.st_mode) &&
1408 (temp[0] != '.' || (temp[1] != '.' && temp[1] != '\0'))) {
1413 /* attach the pathname to the end of the displayed path */
1414 if (disp_pathname[0] == '\0') {
1415 snprintf(tmp2, 1024, "%s", temp);
1417 snprintf(tmp2, 1024, "%s/%s", disp_pathname, temp);
1421 pos = list_core(c, "*", tmp2, lo,
1433 lseek(f->local_file, 0, SEEK_SET);
1445 * cmd_noop(): Handles the NOOP command. Does nothing, doesn't even
1446 * reset the timeout.
1448 int cmd_noop(struct conn * const c)
1450 numeric(c, 200, "NOOP command successful.");
1455 * cmd_syst(): Handles the SYST command. Returns the system identification.
1457 int cmd_syst(struct conn * const c)
1459 numeric(c, 215, "UNIX Type: L%u", NBBY);
1464 * cmd_type(): Handles the TYPE command.
1466 int cmd_type(struct conn * const c)
1469 c->recv_buf[0] &= (255-32); /* convert to upper case */
1470 if (c->recv_buf[0] == 'A') {
1472 numeric(c, 200, "Type is ASCII.");
1473 } else if (c->recv_buf[0] == 'I') {
1475 numeric(c, 200, "Type is IMAGE.");
1477 numeric(c, 504, "Unknown type.");
1480 numeric(c, 200, "TYPE ignored (always I)");
1486 * cmd_mode(): Handles the MODE command. Only stream mode is supported.
1488 int cmd_mode(struct conn * const c)
1490 c->recv_buf[0] &= (255-32); /* convert to upper case */
1491 if (c->recv_buf[0] == 'S') {
1492 numeric(c, 200, "Mode is STREAM.");
1494 numeric(c, 504, "Unknown mode.");
1500 * cmd_stru(): Handles the STRU command. Only file mode is supported.
1502 int cmd_stru(struct conn * const c)
1504 c->recv_buf[0] &= (255-32); /* convert to upper case */
1505 if (c->recv_buf[0] == 'F') {
1506 numeric(c, 200, "Structure is FILE.");
1508 numeric(c, 504, "Unknown structure.");
1514 * cmd_help(): Handle the HELP command. I'm sorry, but I'm unwilling
1515 * to use a lot of space to explain the RFCs in such a message,
1516 * and BetaFTPD doesn't have any special things that should
1517 * be noted anywhere. Thus, this message is close to empty. I
1518 * feel that a 5xx entry would have been better, but that is
1521 * As with ACCT, this command is supposed to be executed from
1522 * everywhere, so we have to run without setuid. I don't like
1523 * it, but at the same time I have to idea what could go
1526 * Perhaps I should make this message sound a little less
1527 * like an error, since the error code is intended for helpful
1530 int cmd_help(struct conn * const c)
1532 numeric(c, 414, "Sorry, no detailed help; use standard FTP commands.");
1537 * cmd_quit(): Handles the QUIT command, which shuts down the control
1540 int cmd_quit(struct conn * const c)
1542 numeric(c, 221, "Have a nice day!");
1548 * cmd_rein(): Handle the REIN command, which does close to a full reset
1549 * of the connection. Much of the code here is intentionally
1550 * copied directly from alloc_new_conn() -- perhaps we should
1553 int cmd_rein(struct conn * const c)
1555 destroy_ftran(c->transfer);
1556 c->buf_len = c->auth = c->rest_pos = 0;
1558 /* equals: strcpy(c->curr_dir, "/") ; strcpy(c->last_cmd, ""); */
1559 c->curr_dir[0] = '/';
1561 c->curr_dir[1] = c->last_cmd[0] = '\0';
1563 c->curr_dir[1] = '\0';
1566 time(&(c->last_transfer));
1567 numeric(c, 220, "BetaFTPD " VERSION " ready.");
1574 * cmd_exit(): Handles the EXIT command, my own `extension' to the
1575 * FTP protocol... IMPORTANT: Only to be used for profiling
1576 * purposes!! (It's needed to get some profiling data out
1577 * of the server after compiling it with -pg, since such data
1578 * is only written on a clear exit()). Any user (even those
1579 * not logged in) can issue an EXIT, and make the server shut
1580 * down without clearing any sockets etc. In other words:
1581 * Don't use it on a production site.
1583 void cmd_exit(struct conn * const c)
1585 while (first_conn->next_conn)
1586 destroy_conn(first_conn->next_conn);
1593 * Gets a command from c->recv_buf, determines which command
1594 * it is, sets proper effective user-ID and calls the command
1595 * handler. Finally, it cleans up.
1597 * To me, this command seems optimizable, but I'm not really
1600 void parse_command(struct conn *c)
1603 const struct handler *h = handler_table; /* first entry */
1605 if (c == NULL) return;
1607 /* strip any leading non-ASCII characters (including CR/LFs) */
1608 while (c->buf_len > 0 && (c->recv_buf[0] < 'a' || c->recv_buf[0] > 'z')
1609 && (c->recv_buf[0] < 'A' || c->recv_buf[0] > 'Z')) {
1610 remove_bytes(c, 1); /* not good */
1613 /* scan, searching for CR or LF */
1614 cmlen = strcspn(c->recv_buf, "\r\n");
1615 if (cmlen >= c->buf_len) return;
1618 strncpy(c->last_cmd, c->recv_buf, cmlen);
1619 c->last_cmd[cmlen] = 0;
1623 if ((cmlen >= (strlen(h->cmd_name) + h->add_cmlen)) &&
1624 (strncasecmp(c->recv_buf, h->cmd_name, strlen(h->cmd_name)) == 0)) {
1625 if (c->auth < h->min_auth) {
1626 numeric(c, 503, "Please login with USER and PASS.");
1627 while (c->recv_buf[0] != '\n') remove_bytes(c, 1);
1639 remove_bytes(c, strlen(h->cmd_name));
1640 cmlen -= strlen(h->cmd_name);
1641 while (c->recv_buf[0] == ' ') {
1646 schar = c->recv_buf[cmlen];
1647 c->recv_buf[cmlen] = 0;
1649 /* result of zero means the connection is freed */
1650 if (h->callback(c)) {
1651 c->recv_buf[cmlen] = schar;
1653 if (h->do_setuid) seteuid(getuid());
1655 remove_bytes(c, cmlen);
1660 } while ((++h)->callback != NULL);
1662 numeric(c, 500, "Sorry, no such command.");
1663 remove_bytes(c, cmlen);
1667 * prepare_for_transfer():
1668 * Prepares an ftran object for a file transfer, setting
1669 * file size, opening sockets etc.
1671 * nonroot notice: prepare_for_transfer() assumes all access
1672 * checks are already done.
1674 void prepare_for_transfer(struct ftran *f)
1677 #warning No nonroot checking for prepare_for_transfer() yet
1681 /* mmap doesn't make temp files for dir listings */
1682 if (!f->dir_listing) {
1685 f->size = lseek(f->local_file, 0, SEEK_END);
1688 if (f->upload == 0 || f->append == 0 || f->owner->rest_pos != 0)
1690 lseek(f->local_file, f->owner->rest_pos, SEEK_SET);
1695 if (f->state == 1) { /* PASV connection */
1696 f->state = 2; /* waiting */
1697 } else if (f->state == 3) { /* PORT connection */
1699 connect(f->sock, (struct sockaddr *)&f->sin, sizeof(f->sin));
1700 add_fd(f->sock, POLLOUT);
1702 time(&(f->tran_start));
1707 * Takes a mode_t argument (from a `struct stat'), and
1708 * returns the proper dirlist letter for that type.
1710 * Note: S_IFLNK seems to be broken, or perhaps I just have
1711 * missed something (S_IFLNK is always set for all *files* on
1712 * my glibc 2.0.111 system).
1714 * The most common cases are put first, for speed :-)
1716 char decode_mode(mode_t mode) {
1717 if (S_ISREG(mode)) return '-';
1718 if (S_ISDIR(mode)) return 'd';
1719 if (S_ISLNK(mode)) return 'l';
1720 if (S_ISBLK(mode)) return 'b';
1721 if (S_ISCHR(mode)) return 'c';
1722 if (S_ISSOCK(mode)) return 's';
1723 if (S_ISFIFO(mode)) return 'f';
1730 * Take an FTP path, do all neccessary root_dir checks,
1731 * change to the correct directory and return the proper
1732 * file name to open/stat/whatever. The path returned is
1733 * relative to the current directory (NOT absolute). chdir()
1734 * in any way will `destroy' this argument.
1736 * Note that `path' will be _changed_, and used as a return pointer
1737 * base. Do not attempt to free the result from this function --
1738 * if you need to, free path instead.
1740 char *translate_path(struct conn * const c, char * const path)
1744 /* chdir to the right dir, then chop it off */
1747 ptr = strrchr(path, '/');
1749 char save_char = ptr[0];
1752 if (do_chdir(c, path) == -1) {
1765 * Opens the file PATH with access parameters FLAGS, translating
1766 * paths and checking permissions as neccessary. Generally, this
1767 * should be used whenever you need an open().
1769 * The parameters might be a bit confusing. To clarify them a bit:
1770 * c: IN/OUT (will be changed)
1771 * path: IN (but _will_ be changed)
1776 int do_openfile(struct conn * const c, char * const path,
1777 char * const filename, const int flags
1779 , const int check_permission
1787 if (nr_check_permission(c->uid, path, check_permission, 0, NULL) == -1) {
1792 ptr = translate_path(c, c->recv_buf);
1793 if (ptr == NULL) return -1;
1796 if ((flags & O_CREAT) == 0) {
1798 TRAP_ERROR(stat(ptr, &buf) == -1, 550, return -2);
1799 if (!S_ISREG(buf.st_mode)) {
1800 numeric(c, 550, "Not a plain file.", ptr);
1807 if (filename != NULL) { /* filename should always be != NULL */
1808 strcpy(filename, ptr);
1810 return open(ptr, flags, 0666);
1814 * prepare_for_listing():
1815 * Parse list options, put them back into the list_options
1816 * structure lo, and make temporary room for the list.
1818 int prepare_for_listing(struct conn * const c, char ** const ptr,
1819 struct list_options * const lo)
1824 struct ftran *f = c->transfer;
1826 char *optr = NULL, *fptr = NULL;
1832 #warning No nonroot checking for prepare_for_listing() yet
1835 if ((f == NULL) || ((f->state != 1) && (f->state != 3))) {
1836 numeric(c, 425, "No data connection set up; please use PASV or PORT.");
1841 * A little parameter scanning is required here. There can only
1842 * be two parts: the directory name, and any options. We'll find
1843 * any options first.
1845 if (c->recv_buf[0] == '-') {
1848 optr = strstr(c->recv_buf, " -");
1851 /* Then see if there are any options to parse. */
1854 switch (*optr & (255-32)) { /* uppercase */
1855 case 'R': /* actually case sensitive... */
1859 lo->long_listing = 1;
1876 /* then we chdir to the dir in fptr (if any) */
1877 tmp = fptr ? strrchr(fptr, '/') : NULL;
1880 if (do_chdir(c, fptr) == -1) return -1;
1883 /* current directory */
1884 TRAP_ERROR(chdir(c->curr_dir) == -1, 550, return -1);
1887 /* if no argument, choose all files */
1888 if (fptr == NULL || fptr[0] == 0) fptr = "*";
1893 if (nr_check_permission(c->uid, chd, 4, 1, NULL) == -1) {
1894 numeric(c, 550, "Permission denied");
1900 tfname = tempnam(NULL, "ftp");
1903 if (tfname == NULL) tfname = tempnam("/", "ftp");
1906 TRAP_ERROR(tfname == NULL, 550, return -1);
1907 strcpy(f->filename, tfname);
1910 f->local_file = open(f->filename, O_RDWR | O_CREAT | O_TRUNC, 0666);
1911 TRAP_ERROR(f->local_file == -1, 550, return -1);
1922 * classify(): Takes a mode_t argument (from `struct stat'), and returns
1923 * the parameter to be used in an `ls -F'-style listing.
1925 char classify(const mode_t mode)
1927 if (S_ISREG(mode)) {
1928 if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
1934 if (S_ISDIR(mode)) return '/';
1935 if (S_ISLNK(mode)) return '@';
1936 if (S_ISSOCK(mode)) return '=';
1937 if (S_ISFIFO(mode)) return '|';