]> git.sesse.net Git - betaftpd/blobdiff - cmds.c
Fixed another ordering bug with respect to seteuid() vs. setegid().
[betaftpd] / cmds.c
diff --git a/cmds.c b/cmds.c
index a2e047bc51eef0a54ffc3d8d46ea4f74c74108ba..08095378529aee15ad159caa62543cd32b854119 100644 (file)
--- a/cmds.c
+++ b/cmds.c
@@ -2,7 +2,7 @@
     Copyright (C) 1999-2000 Steinar H. Gunderson
 
     This program is is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License, version 2 if the
+    it under the terms of the GNU General Public License, version 2 of the
     License as published by the Free Software Foundation.
 
     This program is distributed in the hope that it will be useful,
 #include <config.h>
 #endif
 
-#if HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
 #if HAVE_STROPTS_H
 #include <stropts.h>
 #endif
 
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
 #if HAVE_SYS_CONF_H
 #include <sys/conf.h>
 #endif
 #include <fcntl.h>
 #endif
 
-#if HAVE_PWD_H
-#include <pwd.h>
-#endif
-
 #if HAVE_GRP_H
 #include <grp.h>
 #endif
 #include <sys/ioctl.h>
 #endif
 
-#if HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-
 #if HAVE_SYS_STAT_H
 #include <sys/stat.h>
 #endif
 #include <sys/conf.h>
 #endif
 
-#if HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-
 #if HAVE_SHADOW_H
 #include <shadow.h>
 #endif
@@ -321,6 +309,7 @@ int cmd_pass(struct conn * const c)
                c->auth = 0;
        } else {
                c->uid = p->pw_uid;
+               c->gid = p->pw_gid;
                strncpy(c->curr_dir, p->pw_dir, 254);
                c->curr_dir[254] = 0;
        }
@@ -340,7 +329,7 @@ int cmd_pass(struct conn * const c)
                ) {
                        c->auth = 0;
                } else {
-                       c->auth = 3;
+                       c->auth = 4;
                }
        }
 #endif /* !WANT_NONROOT */
@@ -356,6 +345,7 @@ int cmd_pass(struct conn * const c)
                chdir(c->curr_dir);
                dump_file(c, 230, "welcome.msg");
 #endif
+               /* Have a different message for anonymous users? */
                numeric(c, 230, "User logged in.");
        }
        return 1;
@@ -422,9 +412,11 @@ int cmd_port(struct conn * const c)
 #if !WANT_NONROOT
                /* need root privilegies for a short while */
                seteuid(getuid());
+               setegid(getgid());
 #endif
                bind(sock, (struct sockaddr *)&sin, sizeof(sin));
 #if !WANT_NONROOT
+               setegid(c->gid);
                seteuid(c->uid);
 #endif
 
@@ -917,7 +909,7 @@ char conn_state[5][27] = {
        "Waiting for e-mail address",
        "Waiting for password",
        "Logged in",
-       "Waiting for password",         /* actually non-existant user */
+       "Logged in",            /* non-anonymous */
 };
 
 char ftran_state[6][42] = {
@@ -1187,30 +1179,17 @@ void do_listing(struct conn * const c, struct list_options * const lo)
 
 #if WANT_DCACHE
        {
-               struct dcache *d = NULL, *next = first_dcache->next_dcache;
-               struct stat buf;
-
-               if (stat(cwd, &buf) > -1) {
-                       /* run through the linked list */
-                       while (next != NULL) {
-                               d = next;
-                               next = d->next_dcache;
-       
-                               if (buf.st_mtime <= d->generated &&
-                                   strcmp(d->dir_name, cwd) == 0 &&
-                                   strcmp(d->pattern, ptr) == 0 &&
-                                   memcmp(&(d->lo), lo,
-                                          sizeof(struct list_options)) == 0) {
-                                       d->use_count++;
-                                       f->dir_cache = d;
-                                       f->file_data = d->dir_data;
-                                       f->size = d->dir_size;
-                                       f->dir_listing = 1;
-                                       f->pos = 0;
-                                       prepare_for_transfer(f);
-                                       return;
-                               }
-                       }
+               struct dcache *d = find_dcache(cwd, ptr, lo);
+               if (d != NULL) {
+                       d->use_count++;
+                       f->dir_cache = d;
+                       f->file_data = d->dir_data;
+                       f->size = d->dir_size;
+                       f->dir_listing = 1;
+                       f->pos = 0;
+
+                       prepare_for_transfer(f);
+                       return;
                }
        }
 #endif
@@ -1580,7 +1559,7 @@ int cmd_rein(struct conn * const c)
  *             down without clearing any sockets etc. In other words:
  *             Don't use it on a production site.
  */
-void cmd_exit(struct conn * const c)
+int cmd_exit(struct conn * const c)
 {
        while (first_conn->next_conn)
                destroy_conn(first_conn->next_conn);
@@ -1630,9 +1609,11 @@ void parse_command(struct conn *c)
 
 #if !WANT_NONROOT
                                if (h->do_setuid) {
+                                       setegid(c->gid);
                                        seteuid(c->uid);
                                } else {
-                                       seteuid(0);
+                                       seteuid(getuid());
+                                       setegid(getgid());
                                }
 #endif
 
@@ -1650,7 +1631,10 @@ void parse_command(struct conn *c)
                                if (h->callback(c)) {
                                        c->recv_buf[cmlen] = schar;
 #if !WANT_NONROOT
-                                       if (h->do_setuid) seteuid(getuid());
+                                       if (h->do_setuid) {
+                                               seteuid(getuid());
+                                               setegid(getgid());
+                                       }
 #endif
                                        remove_bytes(c, cmlen);
                                }
@@ -1861,7 +1845,7 @@ int prepare_for_listing(struct conn * const c, char ** const ptr,
                        case 'F':
                                lo->classify = 1;
                                break;
-                       case ' ':
+                       case '\0':
                                fptr = optr + 1;
                                *(optr--) = 0;
                                break;
@@ -1872,7 +1856,7 @@ int prepare_for_listing(struct conn * const c, char ** const ptr,
        } else {
                fptr = c->recv_buf;
        }
-       
+
        /* then we chdir to the dir in fptr (if any) */
        tmp = fptr ? strrchr(fptr, '/') : NULL;
        if (tmp != NULL) {
@@ -1885,7 +1869,16 @@ int prepare_for_listing(struct conn * const c, char ** const ptr,
        }
 
        /* if no argument, choose all files */
-       if (fptr == NULL || fptr[0] == 0) fptr = "*";
+       if (fptr == NULL || fptr[0] == 0) {
+               fptr = "*";
+       } else {
+               /* we need to check if the last part is a directory (no -d switch) */
+               struct stat buf;
+               if (stat(fptr, &buf) == 0 && S_ISDIR(buf.st_mode)) {
+                       TRAP_ERROR(chdir(fptr) == -1, 550, return -1);
+                       fptr = "*";
+               }
+       }
        *ptr = fptr;
 
 #if WANT_NONROOT