[comp.unix.wizards] anonymous ftp, and chroot

daemon@watale.waterloo.edu (Watale's Little Helper) (11/27/88)

I have been having trouble trying to get in.ftpd to record all anonymous
ftp activity.  I don't quite understand why, but the problem seems
to be caused by the chroot call.

A trace of in.ftpd shows the following:

[all writes to descriptor three (/dev/log) work fine above this point]
chdir ("/usr/ftp") = 0
open ("/usr/adm/wtmp", 011, 0) = 4
chroot ("/usr/ftp") = 0
write (1, "230 Guest login ok, access restr".., 48) = 48
gettimeofday (0xf7fff388, 0) = 0
getpid () = 6019
[crash, and burn time]
sendto (3, "<31>Nov 25 22:32:07 ftpd[6019]: ".., 42, 0, 0xd4e8, 16) = -1
ENOENT (No such file or directory)

It seems that altering the root directory somehow messes up access to
/dev/log.  I suppose the obvious answer is that /dev/log is no longer
accessible once the chroot("/usr/ftp") takes effect.  But there must
be more to it than that, because /dev/log is opened before the root
directory is changed*.

* It is my understanding that I can open any file, do a chroot, and
still have access to that file until I close it (even if it lies "above"
the new root directory).  Does this statement not hold true for UNIX
domain sockets like /dev/log?  And if so, why?

Assuming that there really is a problem, and I'm not just being
dense, how can I fix in.ftpd to properly log messages after calling chroot?

Thank you for your time.

Mike Adams
mdadams@surya.waterloo.edu

guy@auspex.UUCP (Guy Harris) (11/29/88)

>* It is my understanding that I can open any file, do a chroot, and
>still have access to that file until I close it (even if it lies "above"
>the new root directory).  Does this statement not hold true for UNIX
>domain sockets like /dev/log?

No, if I read the 4.3BSD code correctly, it doesn't.  For one thing, you
don't open UNIX-domain sockets (fixed in 4.4BSD?); you do a "socket"
call that creates a socket that refers to the UNIX-domain
protocol/address family in general, not to some particular "address" in
that family, and then either do a "connect" call to bind it to a
particular address, or specify the address in a "sendto" call.  That's
the point at which the "address" - which, in the UNIX-domain case,
is the pathname of a file such as "/dev/log" - is interpreted, and if
that happens after the "chroot", you lose.

>Assuming that there really is a problem, and I'm not just being
>dense, how can I fix in.ftpd to properly log messages after calling chroot?

It's "syslog" that needs fixing; it should do a "connect" in "openlog",
right after it's created the socket.  Then just make sure "in.ftpd" does
an "openlog" before doing the "chroot".

In fact, the 4.3-tahoe "openlog" does precisely that; if the "connect"
fails, it notes that it is not connected, and tries to do a "connect"
when it does a "syslog".  (The intent behind that is presumably so that
you can call "openlog" before "syslogd" has started up and created the
"/dev/log" socket, and not have it fail, just have it retry later when
"syslogd" may be up and running.)

mouse@mcgill-vision.UUCP (der Mouse) (12/14/88)

In article <3024@watale.waterloo.edu>, daemon@watale.waterloo.edu (Watale's Little Helper) writes:
> I have been having trouble trying to get in.ftpd to record all
> anonymous ftp activity.  I don't quite understand why, but the
> problem seems to be caused by the chroot call.

> A trace of in.ftpd shows the following:
[...]
> chroot ("/usr/ftp") = 0
[...]
> [crash, and burn time]
> sendto (3, "<31>Nov 25 22:32:07 ftpd[6019]: ".., 42, 0, 0xd4e8, 16) = -1
> ENOENT (No such file or directory)

Aha.  That's a sendto(), which passes the address ("/dev/log") at the
time of the sendto(), which is after the chroot.  And after the chroot,
there is no /dev/log.  And even if there were, it wouldn't be the one
syslogd is listening to.  Normally, syslog() would then write it to the
console, but /dev/console doesn't exist either.

What we need is a syslogd that allows tcp connections, or perhaps a
connect() on a datagram socket (I think this might work now).

> It seems that altering the root directory somehow messes up access to
> /dev/log.  I suppose the obvious answer is that /dev/log is no longer
> accessible once the chroot("/usr/ftp") takes effect.

True enough.  The path /dev/log no longer points to what it has to
point to - the inode that's got syslogd's socket attached to it.

> But there must be more to it than that, because /dev/log is opened
> before the root directory is changed*.

/dev/log isn't opened; you can't open sockets[%].  The filesystem is
traversed for /dev/log each time you call syslog() - this is done in
the sendto() kernel implementation.

> * It is my understanding that I can open any file, do a chroot, and
> still have access to that file until I close it (even if it lies
> "above" the new root directory).

This is perfectly true.

> Does this statement not hold true for UNIX domain sockets like
> /dev/log?  And if so, why?

It does hold true; it's just that what's being done (sendto) doesn't
open /dev/log once and then use it.  It's more nearly equivalent to
opening /dev/log, sending, and closing, all within the sendto().

> Assuming that there really is a problem, and I'm not just being
> dense, how can I fix in.ftpd to properly log messages after calling
> chroot?

The proper fix is to rework syslog() and syslogd so they can be made to
work even after the client chroot()s.  This is probably beyond most
people.  I don't see any simple fix.

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu

tadguy@cs.odu.edu (Tad Guy) (12/14/88)

In article <3024@watale.waterloo.edu>, daemon@watale.waterloo.edu writes:
>> [ describes how logging info from ftpd is lost after the chroot() ]

In article <1379@mcgill-vision.UUCP>, mouse@mcgill-vision (der Mouse) writes:
>That's a sendto(), which passes the address ("/dev/log") at the
>time of the sendto(), which is after the chroot.  And after the chroot,
>there is no /dev/log.
> ...
>What we need is a syslogd that allows tcp connections, or perhaps a
>connect() on a datagram socket (I think this might work now).

Yes, this does work in 4.3BSD.

>The proper fix is to rework syslog() and syslogd so they can be made to
>work even after the client chroot()s.  This is probably beyond most
>people.  I don't see any simple fix.

What I did was to connect() the datagram socket to "/dev/log" at the
time of openlog() if LOG_NDELAY was specified, then just use send().
Don't forget to add LOG_NDELAY to the openlog() call in ftpd.c.

My diffs (your line numbers may vary):

*** /usr/src/lib/libc/gen/syslog.c	Wed May  7 18:18:50 1986
--- syslog.c	Tue Dec  6 20:02:27 1988
***************
*** 120,126 ****
  		c = MAXLINE;
  
  	/* output the message to the local logger */
! 	if (sendto(LogFile, outline, c, 0, &SyslogAddr, sizeof SyslogAddr) >= 0)
  		return;
  	if (!(LogStat & LOG_CONS))
  		return;
--- 120,126 ----
  		c = MAXLINE;
  
  	/* output the message to the local logger */
! 	if (send(LogFile, outline, c, 0) >= 0)
  		return;
  	if (!(LogStat & LOG_CONS))
  		return;
***************
*** 167,172 ****
--- 167,173 ----
  	strncpy(SyslogAddr.sa_data, logname, sizeof SyslogAddr.sa_data);
  	if (LogStat & LOG_NDELAY) {
  		LogFile = socket(AF_UNIX, SOCK_DGRAM, 0);
+ 		connect(LogFile, &SyslogAddr, sizeof SyslogAddr);
  		fcntl(LogFile, F_SETFD, 1);
  	}
  }

-- 
Tad Guy              Comp Sci, Old Dominion University, Norfolk, VA  23529-0162
tadguy@cs.odu.edu    tadguy@xanth.cs.odu.edu [128.82.8.1]     tadguy@xanth.uucp

"Think twice before speaking, but don't say `think think click click'."
                                                            -- John Owens

tadguy@cs.odu.edu (Tad Guy) (12/14/88)

In article <3024@watale.waterloo.edu>, daemon@watale.waterloo.edu writes:
>> [ describes how logging info from ftpd is lost after the chroot() ]

In article <1379@mcgill-vision.UUCP>, mouse@mcgill-vision (der Mouse) writes:
>That's a sendto(), which passes the address ("/dev/log") at the
>time of the sendto(), which is after the chroot.  And after the chroot,
>there is no /dev/log.
> ...
>What we need is a syslogd that allows tcp connections, or perhaps a
>connect() on a datagram socket (I think this might work now).

Yes, this does work in 4.3BSD.

>The proper fix is to rework syslog() and syslogd so they can be made to
>work even after the client chroot()s.  This is probably beyond most
>people.  I don't see any simple fix.

What I did was give ftp its own copy of syslog.c, which I modified to
connect() the datagram socket to "/dev/log" at the time of openlog()
if LOG_NDELAY was specified, then just use send().  Don't forget to
add LOG_NDELAY to the openlog() call in ftpd.c, and don't do this to
your system-wide copy of syslog() (as it would break unless openlog()
and LOG_NDELAY are used).  A more generic solution is needed, but this
works fine for ftpd.

My diffs (your line numbers may vary):

*** /usr/src/lib/libc/gen/syslog.c	Wed May  7 18:18:50 1986
--- syslog.c	Tue Dec  6 20:02:27 1988
***************
*** 120,126 ****
  		c = MAXLINE;
  
  	/* output the message to the local logger */
! 	if (sendto(LogFile, outline, c, 0, &SyslogAddr, sizeof SyslogAddr) >= 0)
  		return;
  	if (!(LogStat & LOG_CONS))
  		return;
--- 120,126 ----
  		c = MAXLINE;
  
  	/* output the message to the local logger */
! 	if (send(LogFile, outline, c, 0) >= 0)
  		return;
  	if (!(LogStat & LOG_CONS))
  		return;
***************
*** 167,172 ****
--- 167,173 ----
  	strncpy(SyslogAddr.sa_data, logname, sizeof SyslogAddr.sa_data);
  	if (LogStat & LOG_NDELAY) {
  		LogFile = socket(AF_UNIX, SOCK_DGRAM, 0);
+ 		connect(LogFile, &SyslogAddr, sizeof SyslogAddr);
  		fcntl(LogFile, F_SETFD, 1);
  	}
  }

-- 
Tad Guy              Comp Sci, Old Dominion University, Norfolk, VA  23529-0162
tadguy@cs.odu.edu    tadguy@xanth.cs.odu.edu [128.82.8.1]     tadguy@xanth.uucp

"Think twice before speaking, but don't say `think think click click'."
                                                            -- John Owens

louie@trantor.umd.edu (Louis A. Mamakos) (12/14/88)

In article <6827@xanth.cs.odu.edu> tadguy@cs.odu.edu (Tad Guy) writes:
>
>What I did was to connect() the datagram socket to "/dev/log" at the
>time of openlog() if LOG_NDELAY was specified, then just use send().
>Don't forget to add LOG_NDELAY to the openlog() call in ftpd.c.
>

I made a change like this in our syslog(); consider what happens to
long-lived daemons when /etc/syslogd is restarted for some reason.  The
socket is no longer connected, and logging ceases.

I'd like to see an option to syslog via UDP/SOCK_DGRAM internet sockets,
just like 4.2 did.  In fact, the code in syslogd is already there for
for forwarding log messages to other hosts.  All you need is something in
the library routine syslog().



Louis A. Mamakos  WA3YMH    Internet: louie@TRANTOR.UMD.EDU
University of Maryland, Computer Science Center - Systems Programming

tadguy@cs.odu.edu (Tad Guy) (12/14/88)

[ My apologies if you've seen this article more than once.  I keep
finding errors in it and keep superseding it.  What a great feature... ]

In article <3024@watale.waterloo.edu>, daemon@watale.waterloo.edu writes:
>> [ describes how logging info from ftpd is lost after the chroot() ]

In article <1379@mcgill-vision.UUCP>, mouse@mcgill-vision (der Mouse) writes:
>That's a sendto(), which passes the address ("/dev/log") at the
>time of the sendto(), which is after the chroot.  And after the chroot,
>there is no /dev/log.
> ...
>What we need is a syslogd that allows tcp connections, or perhaps a
>connect() on a datagram socket (I think this might work now).

Yes, this does work in 4.3BSD.

>The proper fix is to rework syslog() and syslogd so they can be made to
>work even after the client chroot()s.  This is probably beyond most
>people.  I don't see any simple fix.

What I did was give ftpd its own copy of syslog.c, which I modified to
connect() the datagram socket to "/dev/log" at the time of openlog()
if LOG_NDELAY was specified, then just use send().  Don't forget to
add LOG_NDELAY to the openlog() call in ftpd.c.  A more generic
solution is needed, but this works fine for ftpd.

My diffs (your line numbers may vary):

*** /usr/src/lib/libc/gen/syslog.c	Wed May  7 18:18:50 1986
--- syslog.c	Tue Dec  6 20:02:27 1988
***************
*** 120,126 ****
  		c = MAXLINE;
  
  	/* output the message to the local logger */
! 	if (sendto(LogFile, outline, c, 0, &SyslogAddr, sizeof SyslogAddr) >= 0)
  		return;
  	if (!(LogStat & LOG_CONS))
  		return;
--- 120,126 ----
  		c = MAXLINE;
  
  	/* output the message to the local logger */
! 	if (send(LogFile, outline, c, 0) >= 0)
  		return;
  	if (!(LogStat & LOG_CONS))
  		return;
***************
*** 167,172 ****
--- 167,173 ----
  	strncpy(SyslogAddr.sa_data, logname, sizeof SyslogAddr.sa_data);
  	if (LogStat & LOG_NDELAY) {
  		LogFile = socket(AF_UNIX, SOCK_DGRAM, 0);
+ 		connect(LogFile, &SyslogAddr, sizeof SyslogAddr);
  		fcntl(LogFile, F_SETFD, 1);
  	}
  }

-- 
Tad Guy              Comp Sci, Old Dominion University, Norfolk, VA  23529-0162
tadguy@cs.odu.edu    tadguy@xanth.cs.odu.edu [128.82.8.1]     tadguy@xanth.uucp

"Think twice before speaking, but don't say `think think click click'."
                                                            -- John Owens

tadguy@cs.odu.edu (Tad Guy) (12/14/88)

In article <3042@haven.umd.edu>, louie@trantor (Louis A. Mamakos) writes:
>In article <6827@xanth.cs.odu.edu> tadguy@cs.odu.edu (Tad Guy) writes:
>>What I did was to connect() the datagram socket to "/dev/log" at the...
>
>I made a change like this in our syslog(); consider what happens to
>long-lived daemons when /etc/syslogd is restarted for some reason.  The
>socket is no longer connected, and logging ceases.

Sigh, I didn't supersede fast enough...

This is correct.  What I forgot to mention in that earlier version of
my posting was that I gave ftpd its own copy of syslog.c.

The moral of the story is not to post either late at night (when the
first article went out) or early in the morning (when the superseded
artcles went out).  Perhaps in midday...

	...tad

PS: Just for the record I corrected that error the article before I
had read Louis' article. :-)

-- 
Tad Guy         <tadguy@cs.odu.edu>     Old Dominion University, Norfolk, VA