From 4afef59e9cfdc88092899a6abdff720d39b0ddd3 Mon Sep 17 00:00:00 2001
From: oracle <solaris@oracle.com>
Date: Mon, 3 Aug 2015 14:35:43 -0700
Subject: [PATCH 07/34] DTrace support for SFTP

diff -wpruN --no-dereference '--exclude=*.orig' a~/Makefile.in a/Makefile.in
--- a~/Makefile.in	1970-01-01 00:00:00
+++ a/Makefile.in	1970-01-01 00:00:00
@@ -105,6 +105,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
 	monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-ecdsa-sk.o \
 	ssh-ed25519-sk.o ssh-rsa.o dh.o \
 	msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \
+	sftp_provider.o \
 	ssh-pkcs11.o smult_curve25519_ref.o \
 	poly1305.o chacha.o cipher-chachapoly.o cipher-chachapoly-libcrypto.o \
 	ssh-ed25519.o digest-openssl.o digest-libc.o \
@@ -139,7 +140,7 @@ SSHD_SESSION_OBJS=sshd-session.o auth-rh
 	sftp-server.o sftp-common.o \
 	sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \
 	sandbox-seccomp-filter.o sandbox-capsicum.o sandbox-pledge.o \
-	sandbox-solaris.o uidswap.o $(SKOBJS)
+	sandbox-solaris.o uidswap.o sftp_provider.o $(SKOBJS)
 
 SFTP_CLIENT_OBJS=sftp-common.o sftp-client.o sftp-glob.o
 
@@ -159,7 +160,8 @@ SKHELPER_OBJS=	ssh-sk-helper.o ssh-sk.o
 
 SSHKEYSCAN_OBJS=ssh-keyscan.o $(SKOBJS)
 
-SFTPSERVER_OBJS=sftp-common.o sftp-server.o sftp-server-main.o
+SFTPSERVER_OBJS=sftp-common.o sftp-server.o sftp-server-main.o sftp_provider.o
+ROOTDLIBDIR64=$(DESTDIR)/usr/lib/dtrace/64
 
 SFTP_OBJS=	sftp.o sftp-usergroup.o progressmeter.o $(SFTP_CLIENT_OBJS)
 
@@ -275,9 +277,22 @@ $(CONFIGFILES): $(CONFIGFILES_IN)
 moduli:
 	echo
 
+# dtrace sftp
+sftp_provider.h: $(srcdir)/sftp_provider.d
+	/usr/sbin/dtrace -xnolibs -h -s $(srcdir)/sftp_provider.d \
+	    -o $(srcdir)/sftp_provider.h
+
+sftp_provider.o: sftp_provider.d sftp_provider.h sftp-server.o
+	/usr/sbin/dtrace -G -64 -xnolibs -s $(srcdir)/sftp_provider.d \
+	    sftp-server.o -o sftp_provider.o
+
+# special case for sftp-server.o, it includes sftp_provider.h
+sftp-server.o: sftp_provider.h sftp-server.c
+	$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -c $(srcdir)/sftp-server.c
+
 clean:	regressclean
 	rm -f *.o *.lo *.a $(TARGETS) logintest config.cache config.log
-	rm -f *.out core survey
+	rm -f *.out core survey sftp_provider.h
 	rm -f regress/check-perm$(EXEEXT)
 	rm -f regress/mkdtemp$(EXEEXT)
 	rm -f regress/unittests/test_helper/*.a
@@ -440,6 +455,7 @@ install-files:
 	$(INSTALL) -m 644 ssh-keysign.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8
 	$(INSTALL) -m 644 ssh-pkcs11-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8
 	$(INSTALL) -m 644 ssh-sk-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-sk-helper.8
+	mkdir -p $(ROOTDLIBDIR64) && cp $(srcdir)/sftp64.d $(ROOTDLIBDIR64)/
 
 install-sysconf:
 	$(MKDIR_P) $(DESTDIR)$(sysconfdir)
diff -wpruN --no-dereference '--exclude=*.orig' a~/sftp-server.c a/sftp-server.c
--- a~/sftp-server.c	1970-01-01 00:00:00
+++ a/sftp-server.c	1970-01-01 00:00:00
@@ -56,6 +56,9 @@
 
 #include "sftp.h"
 #include "sftp-common.h"
+#ifdef DTRACE_SFTP
+#include "sftp_provider_impl.h"
+#endif
 
 char *sftp_realpath(const char *, char *); /* sftp-realpath.c */
 
@@ -801,16 +804,19 @@ process_read(u_int32_t id)
 	static u_char *buf;
 	static size_t buflen;
 	u_int32_t len;
-	int r, handle, fd, ret, status = SSH2_FX_FAILURE;
+	int r, handle, fd, ret = 0, status = SSH2_FX_FAILURE;
 	u_int64_t off;
+	char *fpath;
 
 	if ((r = get_handle(iqueue, &handle)) != 0 ||
 	    (r = sshbuf_get_u64(iqueue, &off)) != 0 ||
 	    (r = sshbuf_get_u32(iqueue, &len)) != 0)
 		fatal_fr(r, "parse");
 
+	fpath = handle_to_name(handle);
+
 	debug("request %u: read \"%s\" (handle %d) off %llu len %u",
-	    id, handle_to_name(handle), handle, (unsigned long long)off, len);
+	    id, fpath, handle, (unsigned long long)off, len);
 	if ((fd = handle_to_fd(handle)) == -1)
 		goto out;
 	if (len > SFTP_MAX_READ_LENGTH) {
@@ -829,6 +835,9 @@ process_read(u_int32_t id)
 		    strerror(errno));
 		goto out;
 	}
+#ifdef DTRACE_SFTP
+	SFTP_TRANSFER_START_OP("read", fd, fpath, len);
+#endif
 	if (len == 0) {
 		/* weird, but not strictly disallowed */
 		ret = 0;
@@ -841,11 +850,18 @@ process_read(u_int32_t id)
 		status = SSH2_FX_EOF;
 		goto out;
 	}
+#ifdef DTRACE_SFTP
+	SFTP_TRANSFER_DONE_OP("read", fd, fpath, ret);
+#endif
 	send_data(id, buf, ret);
 	handle_update_read(handle, ret);
 	/* success */
 	status = SSH2_FX_OK;
  out:
+#ifdef DTRACE_SFTP
+	if (status != SSH2_FX_OK)
+		SFTP_TRANSFER_DONE_OP("read", fd, fpath, ret);
+#endif
 	if (status != SSH2_FX_OK)
 		send_status(id, status);
 }
@@ -857,14 +873,17 @@ process_write(u_int32_t id)
 	size_t len;
 	int r, handle, fd, ret, status;
 	u_char *data;
+	char *fpath;
 
 	if ((r = get_handle(iqueue, &handle)) != 0 ||
 	    (r = sshbuf_get_u64(iqueue, &off)) != 0 ||
 	    (r = sshbuf_get_string(iqueue, &data, &len)) != 0)
 		fatal_fr(r, "parse");
 
+	fpath = handle_to_name(handle);
+
 	debug("request %u: write \"%s\" (handle %d) off %llu len %zu",
-	    id, handle_to_name(handle), handle, (unsigned long long)off, len);
+	    id, fpath, handle, (unsigned long long)off, len);
 	fd = handle_to_fd(handle);
 
 	if (fd < 0)
@@ -877,7 +896,13 @@ process_write(u_int32_t id)
 			    strerror(errno));
 		} else {
 /* XXX ATOMICIO ? */
+#ifdef DTRACE_SFTP
+			SFTP_TRANSFER_START_OP("write", fd, fpath, len);
+#endif
 			ret = write(fd, data, len);
+#ifdef DTRACE_SFTP
+			SFTP_TRANSFER_DONE_OP("write", fd, fpath, ret);
+#endif
 			if (ret == -1) {
 				status = errno_to_portable(errno);
 				error_f("write \"%.100s\": %s",
diff -wpruN --no-dereference '--exclude=*.orig' a~/sftp64.d a/sftp64.d
--- a~/sftp64.d	1970-01-01 00:00:00
+++ a/sftp64.d	1970-01-01 00:00:00
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#pragma D depends_on library net.d
+#pragma D depends_on library io.d
+#pragma D depends_on module lofs
+
+typedef struct sftpinfo {
+	string sfi_user;		/* user name */
+	string sfi_operation;		/* SFTP Operation */
+	ssize_t sfi_nbytes;		/* bytes transferred, if any */
+	string sfi_pathname;		/* pathname of transfer */
+	string sfi_fsresource;		/* Dataset(ZFS) or resource name */
+} sftpinfo_t;
+
+/*
+ * This structure must match the definition of same in sftp_provider_impl.h.
+ */
+typedef struct sftpproto {
+	int64_t sftp_nbytes;		/* bytes written or read */
+	uint64_t sftp_user;		/* user name */
+	uint64_t sftp_operation;	/* SFTP operation */
+	uint64_t sftp_raddr;		/* remote address */
+	uint64_t sftp_pathname;		/* path with file name */
+	int32_t sftp_fd;		/* fd for transfer, if any */
+} sftpproto_t;
+
+#pragma D binding "1.6.1" translator
+translator conninfo_t <sftpproto_t *s> {
+	ci_protocol = "tcp";
+	ci_remote = copyinstr((uintptr_t)
+	    *(uint64_t *)copyin((uintptr_t)&s->sftp_raddr, sizeof (uint64_t)));
+	ci_local = "<unknown>";
+};
+
+#pragma D binding "1.6.1" translator
+translator sftpinfo_t <sftpproto_t *s> {
+	sfi_user = copyinstr((uintptr_t)
+	    *(uint64_t *)copyin((uintptr_t)&s->sftp_user, sizeof (uint64_t)));
+	sfi_operation = copyinstr((uintptr_t)
+	    *(uint64_t *)copyin((uintptr_t)&s->sftp_operation,
+	    sizeof (uint64_t)));
+	sfi_nbytes =
+	    *(uint64_t *)copyin((uintptr_t)&s->sftp_nbytes, sizeof (uint64_t));
+	sfi_fsresource = stringof(fds[*(int32_t *)copyin((uintptr_t)&s->sftp_fd,
+	    sizeof (int32_t))].fi_fs) == "lofs" ? stringof(((struct loinfo *)
+	    curthread->t_procp->p_user.u_finfo.fi_list[*(int32_t *)copyin(
+	    (uintptr_t)&s->sftp_fd, sizeof (int32_t))].uf_file->f_vnode->
+	    v_vfsp->vfs_data)->li_realvfs->vfs_resource->rs_string) :
+	    stringof(curthread->t_procp->p_user.u_finfo.fi_list[
+	    *(int32_t *)copyin((uintptr_t)&s->sftp_fd, sizeof (int32_t))].
+	    uf_file->f_vnode->v_vfsp->vfs_resource->rs_string);
+	sfi_pathname = copyinstr((uintptr_t)*(uint64_t *)copyin(
+	    (uintptr_t)&s->sftp_pathname, sizeof (uint64_t)));
+};
diff -wpruN --no-dereference '--exclude=*.orig' a~/sftp_provider.d a/sftp_provider.d
--- a~/sftp_provider.d	1970-01-01 00:00:00
+++ a/sftp_provider.d	1970-01-01 00:00:00
@@ -0,0 +1,61 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*
+ * We seem currently unable to depend properly on existing D libraries (like
+ * sftp.d). But the definitions for conninfo_t and sftpinfo_t are stored there
+ * (and have to be, since that's where the real translators live). So we're
+ * forced to define something here to satisfy dtrace(8), but none of the
+ * definitions or translators here are actually used.
+ */
+typedef struct sftpinfo {
+	int dummy;
+} sftpinfo_t;
+
+typedef struct sftpproto {
+	int dummy;
+} sftpproto_t;
+
+typedef struct conninfo {
+	int dummy;
+} conninfo_t;
+
+translator conninfo_t <sftpproto_t *dp> {
+};
+
+translator sftpinfo_t <sftpproto_t *dp> {
+};
+
+provider sftp {
+	probe transfer__start(sftpproto_t *p) :
+	    (conninfo_t *p, sftpinfo_t *p);
+	probe transfer__done(sftpproto_t *p) :
+	    (conninfo_t *p, sftpinfo_t *p);
+};
+
+#pragma D attributes Evolving/Evolving/ISA provider sftp provider
+#pragma D attributes Private/Private/Unknown provider sftp module
+#pragma D attributes Private/Private/Unknown provider sftp function
+#pragma D attributes Private/Private/ISA provider sftp name
+#pragma D attributes Evolving/Evolving/ISA provider sftp args
diff -wpruN --no-dereference '--exclude=*.orig' a~/sftp_provider_impl.h a/sftp_provider_impl.h
--- a~/sftp_provider_impl.h	1970-01-01 00:00:00
+++ a/sftp_provider_impl.h	1970-01-01 00:00:00
@@ -0,0 +1,73 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef	_SFTP_PROVIDER_IMPL_H
+#define	_SFTP_PROVIDER_IMPL_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+ * This structure must match the definition of same in sftp.d.
+ */
+typedef struct sftpproto {
+	int64_t sftp_nbytes;		/* bytes writtten or read */
+	const char *sftp_user;		/* user name */
+	const char *sftp_operation;	/* SFTP Operation */
+	const char *sftp_raddr;		/* remote address */
+	const char *sftp_pathname;	/* path with file name */
+	int32_t sftp_fd;		/* fd for transfer, if any */
+} sftpproto_t;
+
+#define	SFTP_TRANSFER_PROTO(proto, op, fd, path, len) \
+	bzero((proto), sizeof (struct sftpproto)); \
+	(proto)->sftp_user = (pw->pw_name ? pw->pw_name : "UNKNOWN"); \
+	(proto)->sftp_operation = (op ? op : "UNKNOWN"); \
+	(proto)->sftp_raddr = (client_addr); \
+	(proto)->sftp_fd = (fd); \
+	(proto)->sftp_pathname = (path ? path : "UNKNOWN"); \
+	(proto)->sftp_nbytes = (len); \
+
+#define	SFTP_TRANSFER_START_OP(op, fd, path, len) \
+	if (SFTP_TRANSFER_START_ENABLED()) { \
+		sftpproto_t proto; \
+		SFTP_TRANSFER_PROTO(&proto, op, fd, path, len); \
+		SFTP_TRANSFER_START(&proto); \
+	} \
+
+#define	SFTP_TRANSFER_DONE_OP(op, fd, path, len) \
+	if (SFTP_TRANSFER_DONE_ENABLED()) { \
+		sftpproto_t proto; \
+		SFTP_TRANSFER_PROTO(&proto, op, fd, path, len); \
+		SFTP_TRANSFER_DONE(&proto); \
+	} \
+
+#include "sftp_provider.h"
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* _SFTP_PROVIDER_IMPL_H */
