SFTP Logging

Jason A . Dour jason at dour.org
Sat Jun 16 00:37:49 EST 2001


On Fri, Jun 15, 2001 at 10:27:54AM +1000, Andrew Bartlett wrote:
> Remember that it will amout to moot unless you use a restricted
> shell, like the one I have posted to this list earlier, as
> otherwise users can just use their own SFTP server - without your
> logging capabilities.

True.  But I'm also coding such a shell to meet my needs for
SFTP/SCP restricted users only.  And I'm also spelunking the OpenSSH
codebase to see about separating authentication and authorization.

I don't know if authent/auhtoriz separation has been discussed
before, but regardless of the authentication method I've allowed, I
need to restrict what a user can do.  I havne't come up with a clear
solution yet, but I've a few ideas forming...


On Thu, Jun 14, 2001 at 06:25:58PM -0700, Jason Stone wrote:
> I'm always in favor of more logging options.

I've attached a diff versus the 2.9p1 release (I apologize for my
lack of CVS-ness).  It covers logging of most major operations.

The logline is constructed to include the parent PID, the UID of the
user, and the UserName of the user for tracking/tie-back purposes:

	sftp-server[PID]: (PPID/UID/UNAME) Entry

Possible cleanups...look at a better way to do sflags_from_portable.
Presently the function that converts portable to "string flags" such
as "(rwacte)" presently uses pointers to modify character values in
a fixed-length string.  I did it this way to avoid using any
string.h functions that are not used throughout the program.

Possible additions...look at logging a virtual current working
directory via logging send_names.  Not great since there really
isn't a CWD with SFTP server, but it is a potential tidbit of
information admins might want.  Also potentially log uses of '..' in
realpath as a paranoia check for admins who might want it.  chroot()
would be a better answer for this paranoia, but I presently do not
have a chroot() solution.


Feedback is appreciated.  I apologize if I'm a bit unorthodox in my
delivery of this contribution...it's been a while since I've been
eye-deep in code (since the birth of suEXEC actually), and I'm a bit
rusty.



Cheers,
Jason
# "Jason A. Dour" <jason at dour.org>                  http://dour.org/
# Founder / Executive Producer - PJ Harvey Online - http://pjh.org/
-------------- next part --------------
*** sftp-server.c.orig	Mon Jun 11 12:18:31 2001
--- sftp-server.c	Fri Jun 15 09:06:31 2001
***************
*** 52,59 ****
  /* Version of client */
  int version;
  
! /* portable attibutes, etc. */
  
  typedef struct Stat Stat;
  
  struct Stat {
--- 52,65 ----
  /* Version of client */
  int version;
  
! /* User information. */
! #define CUNAME				cuname ? cuname : "UNKNOWN"
! struct passwd *upw;
! uid_t cuid;
! pid_t ppid;
! char *cuname;
  
+ /* portable attibutes, etc. */
  typedef struct Stat Stat;
  
  struct Stat {
***************
*** 115,120 ****
--- 121,148 ----
  	return flags;
  }
  
+ void
+ sflags_from_portable(char *psflags, int pflags)
+ {
+ 	if (pflags & SSH2_FXF_READ)
+ 		*psflags = 'r';
+ 	psflags++;
+ 	if (pflags & SSH2_FXF_WRITE)
+ 		*psflags = 'w';
+ 	psflags++;
+ 	if (pflags & SSH2_FXF_APPEND)
+ 		*psflags = 'a';
+ 	psflags++;
+ 	if (pflags & SSH2_FXF_CREAT)
+ 		*psflags = 'c';
+ 	psflags++;
+ 	if (pflags & SSH2_FXF_TRUNC)
+ 		*psflags = 't';
+ 	psflags++;
+ 	if (pflags & SSH2_FXF_EXCL)
+ 		*psflags = 'e';
+ }
+ 
  Attrib *
  get_attrib(void)
  {
***************
*** 370,375 ****
--- 398,404 ----
  
  	version = buffer_get_int(&iqueue);
  	TRACE("client version %d", version);
+ 	log("(%d/%d/%s) Client version %d", ppid, cuid, CUNAME, version);
  	buffer_init(&msg);
  	buffer_put_char(&msg, SSH2_FXP_VERSION);
  	buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
***************
*** 382,388 ****
  {
  	u_int32_t id, pflags;
  	Attrib *a;
! 	char *name;
  	int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
  
  	id = get_int();
--- 411,417 ----
  {
  	u_int32_t id, pflags;
  	Attrib *a;
! 	char *name, sflags[7] = "------";
  	int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
  
  	id = get_int();
***************
*** 390,397 ****
--- 419,428 ----
  	pflags = get_int();		/* portable flags */
  	a = get_attrib();
  	flags = flags_from_portable(pflags);
+ 	sflags_from_portable(&sflags[0], pflags);
  	mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
  	TRACE("open id %d name %s flags %d mode 0%o", id, name, pflags, mode);
+ 	log("(%d/%d/%s) File/Dir opened: %s (%s,%04o)", ppid, cuid, CUNAME, name, sflags, mode);
  	fd = open(name, flags, mode);
  	if (fd < 0) {
  		status = errno_to_portable(errno);
***************
*** 589,594 ****
--- 620,626 ----
  	name = get_string(NULL);
  	a = get_attrib();
  	TRACE("setstat id %d name %s", id, name);
+ 	log("(%d/%d/%s) Permissions altered: %s (%04o).", ppid, cuid, CUNAME, name, a->perm & 0777);
  	if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
  		ret = chmod(name, a->perm & 0777);
  		if (ret == -1)
***************
*** 623,628 ****
--- 655,661 ----
  	TRACE("fsetstat id %d handle %d", id, handle);
  	fd = handle_to_fd(handle);
  	name = handle_to_name(handle);
+ 	log("(%d/%d/%s) Permissions altered: %s (%04o).", ppid, cuid, CUNAME, name, a->perm & 0777);
  	if (fd < 0 || name == NULL) {
  		status = SSH2_FX_FAILURE;
  	} else {
***************
*** 790,795 ****
--- 823,829 ----
  	id = get_int();
  	name = get_string(NULL);
  	TRACE("remove id %d name %s", id, name);
+ 	log("(%d/%d/%s) File deleted: %s", ppid, cuid, CUNAME, name);
  	ret = unlink(name);
  	status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
  	send_status(id, status);
***************
*** 810,815 ****
--- 844,850 ----
  	mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
  	    a->perm & 0777 : 0777;
  	TRACE("mkdir id %d name %s mode 0%o", id, name, mode);
+ 	log("(%d/%d/%s) Directory created: %s", ppid, cuid, CUNAME, name);
  	ret = mkdir(name, mode);
  	status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
  	send_status(id, status);
***************
*** 826,831 ****
--- 861,867 ----
  	id = get_int();
  	name = get_string(NULL);
  	TRACE("rmdir id %d name %s", id, name);
+ 	log("(%d/%d/%s) Directory deleted: %s", ppid, cuid, CUNAME, name);
  	ret = rmdir(name);
  	status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
  	send_status(id, status);
***************
*** 869,874 ****
--- 905,911 ----
  	oldpath = get_string(NULL);
  	newpath = get_string(NULL);
  	TRACE("rename id %d old %s new %s", id, oldpath, newpath);
+ 	log("(%d/%d/%s) File/Dir renamed: %s -> %s", ppid, cuid, CUNAME, oldpath, newpath);
  	/* fail if 'newpath' exists */
  	if (stat(newpath, &st) == -1) {
  		ret = rename(oldpath, newpath);
***************
*** 914,919 ****
--- 951,957 ----
  	oldpath = get_string(NULL);
  	newpath = get_string(NULL);
  	TRACE("symlink id %d old %s new %s", id, oldpath, newpath);
+ 	log("(%d/%d/%s) Symbolic link created: %s -> %s", ppid, cuid, CUNAME, oldpath, newpath);
  	/* fail if 'newpath' exists */
  	if (stat(newpath, &st) == -1) {
  		ret = symlink(oldpath, newpath);
***************
*** 951,956 ****
--- 989,995 ----
  	msg_len = GET_32BIT(cp);
  	if (msg_len > 256 * 1024) {
  		error("bad message ");
+ 		log("(%d/%d/%s) SFTP session closing (%s).", ppid, cuid, CUNAME, "Bad Message");
  		exit(11);
  	}
  	if (buffer_len(&iqueue) < msg_len + 4)
***************
*** 1031,1045 ****
--- 1070,1102 ----
  	int in, out, max;
  	ssize_t len, olen, set_size;
  
+ 
  	/* XXX should use getopt */
  
  	__progname = get_progname(av[0]);
  	handle_init();
  
+ 	/* Initialize the username of the user running the process. */
+ 	cuid = getuid();
+ 	if ((upw = getpwuid(cuid)) == NULL) {
+ 		cuname = NULL;
+ 	} else {
+ 		cuname = upw->pw_name;
+ 	}
+ 
+ 	/* Initialize the parent process ID. */
+ 	ppid = getppid();
+ 
+ 	/* Initialize the logfile, loglevel dependent on DEBUG compile-time setting. */
  #ifdef DEBUG_SFTP_SERVER
  	log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0);
+ #else
+ 	log_init("sftp-server", SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_AUTH, 0);
  #endif
  
+ 	/* Log session start. */
+ 	log("(%d/%d/%s) SFTP session started.", ppid, cuid, CUNAME);
+ 
  	in = dup(STDIN_FILENO);
  	out = dup(STDOUT_FILENO);
  
***************
*** 1073,1078 ****
--- 1130,1136 ----
  		if (select(max+1, rset, wset, NULL, NULL) < 0) {
  			if (errno == EINTR)
  				continue;
+ 			log("(%d/%d/%s) SFTP session closing (%s).", ppid, cuid, CUNAME, "Select Error");
  			exit(2);
  		}
  
***************
*** 1082,1090 ****
--- 1140,1150 ----
  			len = read(in, buf, sizeof buf);
  			if (len == 0) {
  				debug("read eof");
+ 				log("(%d/%d/%s) SFTP session closing (%s).", ppid, cuid, CUNAME, "EOF");
  				exit(0);
  			} else if (len < 0) {
  				error("read error");
+ 				log("(%d/%d/%s) SFTP session closing (%s).", ppid, cuid, CUNAME, "Read Error");
  				exit(1);
  			} else {
  				buffer_append(&iqueue, buf, len);
***************
*** 1095,1100 ****
--- 1155,1161 ----
  			len = write(out, buffer_ptr(&oqueue), olen);
  			if (len < 0) {
  				error("write error");
+ 				log("(%d/%d/%s) SFTP session closing (%s).", ppid, cuid, CUNAME, "Write Error");
  				exit(1);
  			} else {
  				buffer_consume(&oqueue, len);


More information about the openssh-unix-dev mailing list